Files
wxWidgets/src/common/fswatchercmn.cpp
Vadim Zeitlin 3f66f6a5b3 Remove all lines containing cvs/svn "$Id$" keyword.
This keyword is not expanded by Git which means it's not replaced with the
correct revision value in the releases made using git-based scripts and it's
confusing to have lines with unexpanded "$Id$" in the released files. As
expanding them with Git is not that simple (it could be done with git archive
and export-subst attribute) and there are not many benefits in having them in
the first place, just remove all these lines.

If nothing else, this will make an eventual transition to Git simpler.

Closes #14487.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@74602 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2013-07-26 16:02:46 +00:00

327 lines
9.5 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: src/common/fswatchercmn.cpp
// Purpose: wxMswFileSystemWatcher
// Author: Bartosz Bekier
// Created: 2009-05-26
// 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";
case wxFSW_EVENT_ATTRIB: // Currently this is wxGTK-only
return "ATTRIBUTE";
#ifdef wxHAS_INOTIFY
case wxFSW_EVENT_UNMOUNT: // Currently this is wxGTK-only
return "UNMOUNT";
#endif
case wxFSW_EVENT_WARNING:
return "WARNING";
case wxFSW_EVENT_ERROR:
return "ERROR";
}
// should never be reached!
wxFAIL_MSG("Unknown change type");
return "INVALID_TYPE";
}
// ============================================================================
// wxFileSystemWatcherEvent implementation
// ============================================================================
IMPLEMENT_DYNAMIC_CLASS(wxFileSystemWatcherEvent, wxEvent);
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)
{
wxFSWPathType type = wxFSWPath_None;
if ( path.FileExists() )
{
type = wxFSWPath_File;
}
else if ( path.DirExists() )
{
type = wxFSWPath_Dir;
}
else
{
// Don't overreact to being passed a non-existent item. It may have
// only just been deleted, in which case doing nothing is correct
wxLogTrace(wxTRACE_FSWATCHER,
"Can't monitor non-existent path \"%s\" for changes.",
path.GetFullPath());
return false;
}
return AddAny(path, events, type);
}
bool
wxFileSystemWatcherBase::AddAny(const wxFileName& path,
int events,
wxFSWPathType type,
const wxString& filespec)
{
wxString canonical = GetCanonicalPath(path);
if (canonical.IsEmpty())
return false;
// adding a path in a platform specific way
wxFSWatchInfo watch(canonical, events, type, filespec);
if ( !m_service->Add(watch) )
return false;
// on success, either add path to our 'watch-list'
// or, if already watched, inc the refcount. This may happen if
// a dir is Add()ed, then later AddTree() is called on a parent dir
wxFSWatchInfoMap::iterator it = m_watches.find(canonical);
if ( it == m_watches.end() )
{
wxFSWatchInfoMap::value_type val(canonical, watch);
m_watches.insert(val);
}
else
{
wxFSWatchInfo& watch = it->second;
int count = watch.IncRef();
wxLogTrace(wxTRACE_FSWATCHER,
"'%s' is now watched %d times", canonical, count);
}
return true;
}
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));
// Decrement the watch's refcount and remove from watch-list if 0
bool ret = true;
wxFSWatchInfo& watch = it->second;
if ( !watch.DecRef() )
{
// remove in a platform specific way
ret = m_service->Remove(watch);
m_watches.erase(it);
}
return ret;
}
bool wxFileSystemWatcherBase::AddTree(const wxFileName& path, int events,
const wxString& filespec)
{
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,
const wxString& filespec) :
m_watcher(watcher), m_events(events), m_filespec(filespec)
{
}
virtual wxDirTraverseResult OnFile(const wxString& WXUNUSED(filename))
{
// There is no need to watch individual files as we watch the
// parent directory which will notify us about any changes in them.
return wxDIR_CONTINUE;
}
virtual wxDirTraverseResult OnDir(const wxString& dirname)
{
if ( m_watcher->AddAny(wxFileName::DirName(dirname),
m_events, wxFSWPath_Tree, m_filespec) )
{
wxLogTrace(wxTRACE_FSWATCHER,
"--- AddTree adding directory '%s' ---", dirname);
}
return wxDIR_CONTINUE;
}
private:
wxFileSystemWatcherBase* m_watcher;
int m_events;
wxString m_filespec;
};
wxDir dir(path.GetFullPath());
// Prevent asserts or infinite loops in trees containing symlinks
int flags = wxDIR_DIRS;
if ( !path.ShouldFollowLink() )
{
flags |= wxDIR_NO_FOLLOW;
}
AddTraverser traverser(this, events, filespec);
dir.Traverse(traverser, filespec, flags);
// Add the path itself explicitly as Traverse() doesn't return it.
AddAny(path.GetPathWithSep(), events, wxFSWPath_Tree, filespec);
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,
const wxString& filespec) :
m_watcher(watcher), m_filespec(filespec)
{
}
virtual wxDirTraverseResult OnFile(const wxString& WXUNUSED(filename))
{
// We never watch the individual files when watching the tree, so
// nothing to do here.
return wxDIR_CONTINUE;
}
virtual wxDirTraverseResult OnDir(const wxString& dirname)
{
m_watcher->Remove(wxFileName::DirName(dirname));
return wxDIR_CONTINUE;
}
private:
wxFileSystemWatcherBase* m_watcher;
wxString m_filespec;
};
// If AddTree() used a filespec, we must use the same one
wxString canonical = GetCanonicalPath(path);
wxFSWatchInfoMap::iterator it = m_watches.find(canonical);
wxCHECK_MSG( it != m_watches.end(), false,
wxString::Format("Path '%s' is not watched", canonical) );
wxFSWatchInfo watch = it->second;
const wxString filespec = watch.GetFilespec();
#if defined(__WINDOWS__)
// When there's no filespec, the wxMSW AddTree() would have set a watch
// on only the passed 'path'. We must therefore remove only this
if (filespec.empty())
{
return Remove(path);
}
// Otherwise fall through to the generic implementation
#endif // __WINDOWS__
wxDir dir(path.GetFullPath());
// AddTree() might have used the wxDIR_NO_FOLLOW to prevent asserts or
// infinite loops in trees containing symlinks. We need to do the same
// or we'll try to remove unwatched items. Let's hope the caller used
// the same ShouldFollowLink() setting as in AddTree()...
int flags = wxDIR_DIRS;
if ( !path.ShouldFollowLink() )
{
flags |= wxDIR_NO_FOLLOW;
}
RemoveTraverser traverser(this, filespec);
dir.Traverse(traverser, filespec, flags);
// As in AddTree() above, handle the path itself explicitly.
Remove(path);
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