]>
git.saurik.com Git - wxWidgets.git/blob - src/common/fswatchercmn.cpp
89cb09e4a8c8f41bd4c33619143d78c50ce2382a
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/fswatchercmn.cpp
3 // Purpose: wxMswFileSystemWatcher
4 // Author: Bartosz Bekier
7 // Copyright: (c) 2009 Bartosz Bekier <bartosz.bekier@gmail.com>
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
20 #include "wx/fswatcher.h"
21 #include "wx/private/fswatcher.h"
23 // ============================================================================
25 // ============================================================================
27 wxDEFINE_EVENT(wxEVT_FSWATCHER
, wxFileSystemWatcherEvent
);
29 static wxString
GetFSWEventChangeTypeName(int type
)
33 case wxFSW_EVENT_CREATE
:
35 case wxFSW_EVENT_DELETE
:
37 case wxFSW_EVENT_RENAME
:
39 case wxFSW_EVENT_MODIFY
:
41 case wxFSW_EVENT_ACCESS
:
45 // should never be reached!
46 wxFAIL_MSG("Unknown change type");
47 return "INVALID_TYPE";
51 // ============================================================================
52 // wxFileSystemWatcherEvent implementation
53 // ============================================================================
55 wxString
wxFileSystemWatcherEvent::ToString() const
57 return wxString::Format("FSW_EVT type=%d (%s) path='%s'", m_changeType
,
58 GetFSWEventChangeTypeName(m_changeType
), GetPath().GetFullPath());
62 // ============================================================================
63 // wxFileSystemWatcherEvent implementation
64 // ============================================================================
66 wxFileSystemWatcherBase::wxFileSystemWatcherBase() :
67 m_service(0), m_owner(this)
71 wxFileSystemWatcherBase::~wxFileSystemWatcherBase()
80 bool wxFileSystemWatcherBase::Add(const wxFileName
& path
, int events
)
82 wxFSWPathType type
= wxFSWPath_None
;
83 if ( path
.FileExists() )
85 type
= wxFSWPath_File
;
87 else if ( path
.DirExists() )
93 wxLogError(_("Can't monitor non-existent path \"%s\" for changes."),
98 return AddAny(path
, events
, type
);
102 wxFileSystemWatcherBase::AddAny(const wxFileName
& path
,
105 const wxString
& filespec
)
107 wxString canonical
= GetCanonicalPath(path
);
108 if (canonical
.IsEmpty())
111 // adding a path in a platform specific way
112 wxFSWatchInfo
watch(canonical
, events
, type
, filespec
);
113 if ( !m_service
->Add(watch
) )
116 // on success, either add path to our 'watch-list'
117 // or, if already watched, inc the refcount. This may happen if
118 // a dir is Add()ed, then later AddTree() is called on a parent dir
119 wxFSWatchInfoMap::iterator it
= m_watches
.find(canonical
);
120 if ( it
== m_watches
.end() )
122 wxFSWatchInfoMap::value_type
val(canonical
, watch
);
123 m_watches
.insert(val
).second
;
127 wxFSWatchInfo
& watch
= it
->second
;
128 int count
= watch
.IncRef();
129 wxLogTrace(wxTRACE_FSWATCHER
,
130 "'%s' is now watched %d times", canonical
, count
);
135 bool wxFileSystemWatcherBase::Remove(const wxFileName
& path
)
137 // args validation & consistency checks
138 wxString canonical
= GetCanonicalPath(path
);
139 if (canonical
.IsEmpty())
142 wxFSWatchInfoMap::iterator it
= m_watches
.find(canonical
);
143 wxCHECK_MSG(it
!= m_watches
.end(), false,
144 wxString::Format("Path '%s' is not watched", canonical
));
146 // Decrement the watch's refcount and remove from watch-list if 0
148 wxFSWatchInfo
& watch
= it
->second
;
149 if ( !watch
.DecRef() )
151 // remove in a platform specific way
152 ret
= m_service
->Remove(watch
);
159 bool wxFileSystemWatcherBase::AddTree(const wxFileName
& path
, int events
,
160 const wxString
& filespec
)
162 if (!path
.DirExists())
165 // OPT could be optimised if we stored information about relationships
167 class AddTraverser
: public wxDirTraverser
170 AddTraverser(wxFileSystemWatcherBase
* watcher
, int events
,
171 const wxString
& filespec
) :
172 m_watcher(watcher
), m_events(events
), m_filespec(filespec
)
176 virtual wxDirTraverseResult
OnFile(const wxString
& WXUNUSED(filename
))
178 // There is no need to watch individual files as we watch the
179 // parent directory which will notify us about any changes in them.
180 return wxDIR_CONTINUE
;
183 virtual wxDirTraverseResult
OnDir(const wxString
& dirname
)
185 if ( m_watcher
->AddAny(wxFileName::DirName(dirname
),
186 m_events
, wxFSWPath_Tree
, m_filespec
) )
188 wxLogTrace(wxTRACE_FSWATCHER
,
189 "--- AddTree adding directory '%s' ---", dirname
);
191 return wxDIR_CONTINUE
;
195 wxFileSystemWatcherBase
* m_watcher
;
200 wxDir
dir(path
.GetFullPath());
201 AddTraverser
traverser(this, events
, filespec
);
202 dir
.Traverse(traverser
, filespec
);
204 // Add the path itself explicitly as Traverse() doesn't return it.
205 AddAny(path
.GetPathWithSep(), events
, wxFSWPath_Tree
, filespec
);
210 bool wxFileSystemWatcherBase::RemoveTree(const wxFileName
& path
)
212 if (!path
.DirExists())
215 // OPT could be optimised if we stored information about relationships
217 class RemoveTraverser
: public wxDirTraverser
220 RemoveTraverser(wxFileSystemWatcherBase
* watcher
,
221 const wxString
& filespec
) :
222 m_watcher(watcher
), m_filespec(filespec
)
226 virtual wxDirTraverseResult
OnFile(const wxString
& WXUNUSED(filename
))
228 // We never watch the individual files when watching the tree, so
229 // nothing to do here.
230 return wxDIR_CONTINUE
;
233 virtual wxDirTraverseResult
OnDir(const wxString
& dirname
)
235 m_watcher
->Remove(wxFileName::DirName(dirname
));
236 return wxDIR_CONTINUE
;
240 wxFileSystemWatcherBase
* m_watcher
;
244 // If AddTree() used a filespec, we must use the same one
245 wxString canonical
= GetCanonicalPath(path
);
246 wxFSWatchInfoMap::iterator it
= m_watches
.find(canonical
);
247 wxCHECK_MSG( it
!= m_watches
.end(), false,
248 wxString::Format("Path '%s' is not watched", canonical
) );
249 wxFSWatchInfo watch
= it
->second
;
250 const wxString filespec
= watch
.GetFilespec();
252 #if defined(__WINDOWS__)
253 // When there's no filespec, the wxMSW AddTree() would have set a watch
254 // on only the passed 'path'. We must therefore remove only this
255 if (filespec
.empty())
259 // Otherwise fall through to the generic implementation
260 #endif // __WINDOWS__
262 wxDir
dir(path
.GetFullPath());
263 RemoveTraverser
traverser(this, filespec
);
264 dir
.Traverse(traverser
, filespec
);
266 // As in AddTree() above, handle the path itself explicitly.
272 bool wxFileSystemWatcherBase::RemoveAll()
274 m_service
->RemoveAll();
279 int wxFileSystemWatcherBase::GetWatchedPathsCount() const
281 return m_watches
.size();
284 int wxFileSystemWatcherBase::GetWatchedPaths(wxArrayString
* paths
) const
286 wxCHECK_MSG( paths
!= NULL
, -1, "Null array passed to retrieve paths");
288 wxFSWatchInfoMap::const_iterator it
= m_watches
.begin();
289 for ( ; it
!= m_watches
.end(); ++it
)
291 paths
->push_back(it
->first
);
294 return m_watches
.size();
297 #endif // wxUSE_FSWATCHER