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 wxCHECK_MSG(m_watches
.find(canonical
) == m_watches
.end(), false,
112 wxString
::Format("Path '%s' is already watched", canonical
));
114 // adding a path in a platform specific way
115 wxFSWatchInfo
watch(canonical
, events
, type
, filespec
);
116 if ( !m_service
->Add(watch
) )
119 // on success, add path to our 'watch-list'
120 wxFSWatchInfoMap
::value_type
val(canonical
, watch
);
121 return m_watches
.insert(val
).second
;
124 bool wxFileSystemWatcherBase
::Remove(const wxFileName
& path
)
126 // args validation & consistency checks
127 wxString canonical
= GetCanonicalPath(path
);
128 if (canonical
.IsEmpty())
131 wxFSWatchInfoMap
::iterator it
= m_watches
.find(canonical
);
132 wxCHECK_MSG(it
!= m_watches
.end(), false,
133 wxString
::Format("Path '%s' is not watched", canonical
));
135 // remove from watch-list
136 wxFSWatchInfo watch
= it
->second
;
139 // remove in a platform specific way
140 return m_service
->Remove(watch
);
143 bool wxFileSystemWatcherBase
::AddTree(const wxFileName
& path
, int events
,
144 const wxString
& filespec
)
146 if (!path
.DirExists())
149 // OPT could be optimised if we stored information about relationships
151 class AddTraverser
: public wxDirTraverser
154 AddTraverser(wxFileSystemWatcherBase
* watcher
, int events
,
155 const wxString
& filespec
) :
156 m_watcher(watcher
), m_events(events
), m_filespec(filespec
)
160 // CHECK we choose which files to delegate to Add(), maybe we should pass
161 // all of them to Add() and let it choose? this is useful when adding a
162 // file to a dir that is already watched, then not only should we know
163 // about that, but Add() should also behave well then
164 virtual wxDirTraverseResult
OnFile(const wxString
& filename
)
166 if ( m_watcher
->AddAny(wxFileName
::FileName(filename
),
167 m_events
, wxFSWPath_File
) )
169 wxLogTrace(wxTRACE_FSWATCHER
,
170 "--- AddTree adding file '%s' ---", filename
);
172 return wxDIR_CONTINUE
;
175 virtual wxDirTraverseResult
OnDir(const wxString
& dirname
)
177 // We can't currently watch only the files with the given filespec
178 // in the subdirectories so we only watch subdirectories at all if
179 // we want to watch everything.
180 if ( m_filespec
.empty() )
182 if ( m_watcher
->AddAny(wxFileName
::DirName(dirname
),
183 m_events
, wxFSWPath_Dir
) )
185 wxLogTrace(wxTRACE_FSWATCHER
,
186 "--- AddTree adding directory '%s' ---", dirname
);
189 return wxDIR_CONTINUE
;
193 wxFileSystemWatcherBase
* m_watcher
;
198 wxDir
dir(path
.GetFullPath());
199 AddTraverser
traverser(this, events
, filespec
);
200 dir
.Traverse(traverser
, filespec
);
202 // Add the path itself explicitly as Traverse() doesn't return it.
203 AddAny(path
.GetPathWithSep(), events
, wxFSWPath_Dir
, filespec
);
208 bool wxFileSystemWatcherBase
::RemoveTree(const wxFileName
& path
)
210 if (!path
.DirExists())
213 // OPT could be optimised if we stored information about relationships
215 class RemoveTraverser
: public wxDirTraverser
218 RemoveTraverser(wxFileSystemWatcherBase
* watcher
,
219 const wxString
& filespec
) :
220 m_watcher(watcher
), m_filespec(filespec
)
224 virtual wxDirTraverseResult
OnFile(const wxString
& filename
)
226 m_watcher
->Remove(wxFileName(filename
));
227 return wxDIR_CONTINUE
;
230 virtual wxDirTraverseResult
OnDir(const wxString
& dirname
)
232 // Currently the subdirectories would have been added only if there
235 // Notice that we still need to recurse into them even if we're
236 // using a filespec because they can contain files matching it.
237 if ( m_filespec
.empty() )
239 m_watcher
->Remove(wxFileName
::DirName(dirname
));
242 return wxDIR_CONTINUE
;
246 wxFileSystemWatcherBase
* m_watcher
;
250 // If AddTree() used a filespec, we must use the same one
251 wxString canonical
= GetCanonicalPath(path
);
252 wxFSWatchInfoMap
::iterator it
= m_watches
.find(canonical
);
253 wxCHECK_MSG( it
!= m_watches
.end(), false,
254 wxString
::Format("Path '%s' is not watched", canonical
) );
255 wxFSWatchInfo watch
= it
->second
;
256 const wxString filespec
= watch
.GetFilespec();
258 #if defined(__WINDOWS__)
259 // When there's no filespec, the wxMSW AddTree() would have set a watch
260 // on only the passed 'path'. We must therefore remove only this
261 if (filespec
.empty())
265 // Otherwise fall through to the generic implementation
266 #endif // __WINDOWS__
268 wxDir
dir(path
.GetFullPath());
269 RemoveTraverser
traverser(this, filespec
);
270 dir
.Traverse(traverser
, filespec
);
272 // As in AddTree() above, handle the path itself explicitly.
278 bool wxFileSystemWatcherBase
::RemoveAll()
280 m_service
->RemoveAll();
285 int wxFileSystemWatcherBase
::GetWatchedPathsCount() const
287 return m_watches
.size();
290 int wxFileSystemWatcherBase
::GetWatchedPaths(wxArrayString
* paths
) const
292 wxCHECK_MSG( paths
!= NULL
, -1, "Null array passed to retrieve paths");
294 wxFSWatchInfoMap
::const_iterator it
= m_watches
.begin();
295 for ( ; it
!= m_watches
.end(); ++it
)
297 paths
->push_back(it
->first
);
300 return m_watches
.size();
303 #endif // wxUSE_FSWATCHER