Add the root and all the files in wxFileSystemWatcherBase::AddTree().
[wxWidgets.git] / src / common / fswatchercmn.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/fswatchercmn.cpp
3 // Purpose: wxMswFileSystemWatcher
4 // Author: Bartosz Bekier
5 // Created: 2009-05-26
6 // RCS-ID: $Id$
7 // Copyright: (c) 2009 Bartosz Bekier <bartosz.bekier@gmail.com>
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
13
14 #ifdef __BORLANDC__
15 #pragma hdrstop
16 #endif
17
18 #if wxUSE_FSWATCHER
19
20 #include "wx/fswatcher.h"
21 #include "wx/private/fswatcher.h"
22
23 // ============================================================================
24 // helpers
25 // ============================================================================
26
27 wxDEFINE_EVENT(wxEVT_FSWATCHER, wxFileSystemWatcherEvent);
28
29 static wxString GetFSWEventChangeTypeName(int type)
30 {
31 switch (type)
32 {
33 case wxFSW_EVENT_CREATE:
34 return "CREATE";
35 case wxFSW_EVENT_DELETE:
36 return "DELETE";
37 case wxFSW_EVENT_RENAME:
38 return "RENAME";
39 case wxFSW_EVENT_MODIFY:
40 return "MODIFY";
41 case wxFSW_EVENT_ACCESS:
42 return "ACCESS";
43 }
44
45 // should never be reached!
46 wxFAIL_MSG("Unknown change type");
47 return "INVALID_TYPE";
48 }
49
50
51 // ============================================================================
52 // wxFileSystemWatcherEvent implementation
53 // ============================================================================
54
55 wxString wxFileSystemWatcherEvent::ToString() const
56 {
57 return wxString::Format("FSW_EVT type=%d (%s) path='%s'", m_changeType,
58 GetFSWEventChangeTypeName(m_changeType), GetPath().GetFullPath());
59 }
60
61
62 // ============================================================================
63 // wxFileSystemWatcherEvent implementation
64 // ============================================================================
65
66 wxFileSystemWatcherBase::wxFileSystemWatcherBase() :
67 m_service(0), m_owner(this)
68 {
69 }
70
71 wxFileSystemWatcherBase::~wxFileSystemWatcherBase()
72 {
73 RemoveAll();
74 if (m_service)
75 {
76 delete m_service;
77 }
78 }
79
80 bool wxFileSystemWatcherBase::Add(const wxFileName& path, int events)
81 {
82 wxFSWPathType type = wxFSWPath_None;
83 if ( path.FileExists() )
84 {
85 type = wxFSWPath_File;
86 }
87 else if ( path.DirExists() )
88 {
89 type = wxFSWPath_Dir;
90 }
91 else
92 {
93 wxLogError(_("Can't monitor non-existent path \"%s\" for changes."),
94 path.GetFullPath());
95 return false;
96 }
97
98 return DoAdd(path, events, type);
99 }
100
101 bool
102 wxFileSystemWatcherBase::DoAdd(const wxFileName& path,
103 int events,
104 wxFSWPathType type)
105 {
106 wxString canonical = GetCanonicalPath(path);
107 if (canonical.IsEmpty())
108 return false;
109
110 wxCHECK_MSG(m_watches.find(canonical) == m_watches.end(), false,
111 wxString::Format("Path '%s' is already watched", canonical));
112
113 // adding a path in a platform specific way
114 wxFSWatchInfo watch(canonical, events, type);
115 if ( !m_service->Add(watch) )
116 return false;
117
118 // on success, add path to our 'watch-list'
119 wxFSWatchInfoMap::value_type val(canonical, watch);
120 return m_watches.insert(val).second;
121 }
122
123 bool wxFileSystemWatcherBase::Remove(const wxFileName& path)
124 {
125 // args validation & consistency checks
126 wxString canonical = GetCanonicalPath(path);
127 if (canonical.IsEmpty())
128 return false;
129
130 wxFSWatchInfoMap::iterator it = m_watches.find(canonical);
131 wxCHECK_MSG(it != m_watches.end(), false,
132 wxString::Format("Path '%s' is not watched", canonical));
133
134 // remove from watch-list
135 wxFSWatchInfo watch = it->second;
136 m_watches.erase(it);
137
138 // remove in a platform specific way
139 return m_service->Remove(watch);
140 }
141
142 bool wxFileSystemWatcherBase::AddTree(const wxFileName& path, int events,
143 const wxString& filter)
144 {
145 if (!path.DirExists())
146 return false;
147
148 // OPT could be optimised if we stored information about relationships
149 // between paths
150 class AddTraverser : public wxDirTraverser
151 {
152 public:
153 AddTraverser(wxFileSystemWatcherBase* watcher, int events) :
154 m_watcher(watcher), m_events(events)
155 {
156 }
157
158 // CHECK we choose which files to delegate to Add(), maybe we should pass
159 // all of them to Add() and let it choose? this is useful when adding a
160 // file to a dir that is already watched, then not only should we know
161 // about that, but Add() should also behave well then
162 virtual wxDirTraverseResult OnFile(const wxString& filename)
163 {
164 wxLogTrace(wxTRACE_FSWATCHER,
165 "--- AddTree adding file '%s' ---", filename);
166 m_watcher->DoAdd(wxFileName::FileName(filename),
167 m_events, wxFSWPath_File);
168 return wxDIR_CONTINUE;
169 }
170
171 virtual wxDirTraverseResult OnDir(const wxString& dirname)
172 {
173 wxLogTrace(wxTRACE_FSWATCHER,
174 "--- AddTree adding directory '%s' ---", dirname);
175 // we add as much as possible and ignore errors
176 m_watcher->DoAdd(wxFileName::DirName(dirname),
177 m_events, wxFSWPath_Dir);
178 return wxDIR_CONTINUE;
179 }
180
181 private:
182 wxFileSystemWatcherBase* m_watcher;
183 int m_events;
184 wxString m_filter;
185 };
186
187 wxDir dir(path.GetFullPath());
188 AddTraverser traverser(this, events);
189 dir.Traverse(traverser, filter);
190
191 // Add the path itself explicitly as Traverse() doesn't return it.
192 Add(path.GetPathWithSep(), events);
193
194 return true;
195 }
196
197 bool wxFileSystemWatcherBase::RemoveTree(const wxFileName& path)
198 {
199 if (!path.DirExists())
200 return false;
201
202 // OPT could be optimised if we stored information about relationships
203 // between paths
204 class RemoveTraverser : public wxDirTraverser
205 {
206 public:
207 RemoveTraverser(wxFileSystemWatcherBase* watcher) :
208 m_watcher(watcher)
209 {
210 }
211
212 virtual wxDirTraverseResult OnFile(const wxString& filename)
213 {
214 m_watcher->Remove(wxFileName(filename));
215 return wxDIR_CONTINUE;
216 }
217
218 virtual wxDirTraverseResult OnDir(const wxString& dirname)
219 {
220 m_watcher->Remove(wxFileName::DirName(dirname));
221 return wxDIR_CONTINUE;
222 }
223
224 private:
225 wxFileSystemWatcherBase* m_watcher;
226 };
227
228 wxDir dir(path.GetFullPath());
229 RemoveTraverser traverser(this);
230 dir.Traverse(traverser);
231
232 // As in AddTree() above, handle the path itself explicitly.
233 Remove(path);
234
235 return true;
236 }
237
238 bool wxFileSystemWatcherBase::RemoveAll()
239 {
240 m_service->RemoveAll();
241 m_watches.clear();
242 return true;
243 }
244
245 int wxFileSystemWatcherBase::GetWatchedPathsCount() const
246 {
247 return m_watches.size();
248 }
249
250 int wxFileSystemWatcherBase::GetWatchedPaths(wxArrayString* paths) const
251 {
252 wxCHECK_MSG( paths != NULL, -1, "Null array passed to retrieve paths");
253
254 wxFSWatchInfoMap::const_iterator it = m_watches.begin();
255 for ( ; it != m_watches.end(); ++it)
256 {
257 paths->push_back(it->first);
258 }
259
260 return m_watches.size();
261 }
262
263 #endif // wxUSE_FSWATCHER