Files
wxWidgets/src/common/fswatchercmn.cpp
Vadim Zeitlin 6b8ef0b35d Merge SOC2009_FSWATCHER branch into trunk.
Merges everything from the branch with only some minor changes, mostly renamed
wxUSE_FSWATCHER_{INOTIFY,KQUEUE} to wxHAS_{INOTIFY,KQUEUE}.

Add wxFileSystemWatcher and related classes.

Also introduces wxEventLoopSource.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@62474 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2009-10-22 11:35:43 +00:00

233 lines
6.4 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: common/fswatchercmn.cpp
// Purpose: wxMswFileSystemWatcher
// Author: Bartosz Bekier
// Created: 2009-05-26
// RCS-ID: $Id$
// Copyright: (c) 2009 Bartosz Bekier <bartosz.bekier@gmail.com>
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_FSWATCHER
#include "wx/fswatcher.h"
#include "wx/private/fswatcher.h"
// ============================================================================
// helpers
// ============================================================================
wxDEFINE_EVENT(wxEVT_FSWATCHER, wxFileSystemWatcherEvent);
static wxString GetFSWEventChangeTypeName(int type)
{
switch (type)
{
case wxFSW_EVENT_CREATE:
return "CREATE";
case wxFSW_EVENT_DELETE:
return "DELETE";
case wxFSW_EVENT_RENAME:
return "RENAME";
case wxFSW_EVENT_MODIFY:
return "MODIFY";
case wxFSW_EVENT_ACCESS:
return "ACCESS";
}
// should never be reached!
wxFAIL_MSG("Unknown change type");
return "INVALID_TYPE";
}
// ============================================================================
// wxFileSystemWatcherEvent implementation
// ============================================================================
wxString wxFileSystemWatcherEvent::ToString() const
{
return wxString::Format("FSW_EVT type=%d (%s) path='%s'", m_changeType,
GetFSWEventChangeTypeName(m_changeType), GetPath().GetFullPath());
}
// ============================================================================
// wxFileSystemWatcherEvent implementation
// ============================================================================
wxFileSystemWatcherBase::wxFileSystemWatcherBase() :
m_service(0), m_owner(this)
{
}
wxFileSystemWatcherBase::~wxFileSystemWatcherBase()
{
RemoveAll();
if (m_service)
{
delete m_service;
}
}
bool wxFileSystemWatcherBase::Add(const wxFileName& path, int events)
{
// args validation & consistency checks
if (!path.FileExists() && !path.DirExists())
return false;
wxString canonical = GetCanonicalPath(path);
if (canonical.IsEmpty())
return false;
wxCHECK_MSG(m_watches.find(canonical) == m_watches.end(), false,
wxString::Format("Path '%s' is already watched", canonical));
// adding a path in a platform specific way
wxFSWatchInfo watch(canonical, events);
if ( !m_service->Add(watch) )
return false;
// on success, add path to our 'watch-list'
wxFSWatchInfoMap::value_type val(canonical, watch);
return m_watches.insert(val).second;
}
bool wxFileSystemWatcherBase::Remove(const wxFileName& path)
{
// args validation & consistency checks
wxString canonical = GetCanonicalPath(path);
if (canonical.IsEmpty())
return false;
wxFSWatchInfoMap::iterator it = m_watches.find(canonical);
wxCHECK_MSG(it != m_watches.end(), false,
wxString::Format("Path '%s' is not watched", canonical));
// remove from watch-list
wxFSWatchInfo watch = it->second;
m_watches.erase(it);
// remove in a platform specific way
return m_service->Remove(watch);
}
bool wxFileSystemWatcherBase::AddTree(const wxFileName& path, int events,
const wxString& filter)
{
if (!path.DirExists())
return false;
// OPT could be optimised if we stored information about relationships
// between paths
class AddTraverser : public wxDirTraverser
{
public:
AddTraverser(wxFileSystemWatcherBase* watcher, int events) :
m_watcher(watcher), m_events(events)
{
}
// CHECK we choose which files to delegate to Add(), maybe we should pass
// all of them to Add() and let it choose? this is useful when adding a
// file to a dir that is already watched, then not only should we know
// about that, but Add() should also behave well then
virtual wxDirTraverseResult OnFile(const wxString& WXUNUSED(filename))
{
return wxDIR_CONTINUE;
}
virtual wxDirTraverseResult OnDir(const wxString& dirname)
{
wxLogTrace(wxTRACE_FSWATCHER, "--- AddTree adding '%s' ---",
dirname);
// we add as much as possible and ignore errors
m_watcher->Add(wxFileName(dirname), m_events);
return wxDIR_CONTINUE;
}
private:
wxFileSystemWatcherBase* m_watcher;
int m_events;
wxString m_filter;
};
wxDir dir(path.GetFullPath());
AddTraverser traverser(this, events);
dir.Traverse(traverser, filter);
return true;
}
bool wxFileSystemWatcherBase::RemoveTree(const wxFileName& path)
{
if (!path.DirExists())
return false;
// OPT could be optimised if we stored information about relationships
// between paths
class RemoveTraverser : public wxDirTraverser
{
public:
RemoveTraverser(wxFileSystemWatcherBase* watcher) :
m_watcher(watcher)
{
}
virtual wxDirTraverseResult OnFile(const wxString& filename)
{
m_watcher->Remove(wxFileName(filename));
return wxDIR_CONTINUE;
}
virtual wxDirTraverseResult OnDir(const wxString& dirname)
{
m_watcher->RemoveTree(wxFileName(dirname));
return wxDIR_CONTINUE;
}
private:
wxFileSystemWatcherBase* m_watcher;
};
wxDir dir(path.GetFullPath());
RemoveTraverser traverser(this);
dir.Traverse(traverser);
return true;
}
bool wxFileSystemWatcherBase::RemoveAll()
{
m_service->RemoveAll();
m_watches.clear();
return true;
}
int wxFileSystemWatcherBase::GetWatchedPathsCount() const
{
return m_watches.size();
}
int wxFileSystemWatcherBase::GetWatchedPaths(wxArrayString* paths) const
{
wxCHECK_MSG( paths != NULL, -1, "Null array passed to retrieve paths");
wxFSWatchInfoMap::const_iterator it = m_watches.begin();
for ( ; it != m_watches.end(); ++it)
{
paths->push_back(it->first);
}
return m_watches.size();
}
#endif // wxUSE_FSWATCHER