]> git.saurik.com Git - wxWidgets.git/blob - src/common/fswatchercmn.cpp
No changes, just remove unused part of expression.
[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 case wxFSW_EVENT_ATTRIB: // Currently this is wxGTK-only
44 return "ATTRIBUTE";
45 #ifdef wxHAS_INOTIFY
46 case wxFSW_EVENT_UNMOUNT: // Currently this is wxGTK-only
47 return "UNMOUNT";
48 #endif
49 case wxFSW_EVENT_WARNING:
50 return "WARNING";
51 case wxFSW_EVENT_ERROR:
52 return "ERROR";
53 }
54
55 // should never be reached!
56 wxFAIL_MSG("Unknown change type");
57 return "INVALID_TYPE";
58 }
59
60
61 // ============================================================================
62 // wxFileSystemWatcherEvent implementation
63 // ============================================================================
64
65 wxString wxFileSystemWatcherEvent::ToString() const
66 {
67 return wxString::Format("FSW_EVT type=%d (%s) path='%s'", m_changeType,
68 GetFSWEventChangeTypeName(m_changeType), GetPath().GetFullPath());
69 }
70
71
72 // ============================================================================
73 // wxFileSystemWatcherEvent implementation
74 // ============================================================================
75
76 wxFileSystemWatcherBase::wxFileSystemWatcherBase() :
77 m_service(0), m_owner(this)
78 {
79 }
80
81 wxFileSystemWatcherBase::~wxFileSystemWatcherBase()
82 {
83 RemoveAll();
84 if (m_service)
85 {
86 delete m_service;
87 }
88 }
89
90 bool wxFileSystemWatcherBase::Add(const wxFileName& path, int events)
91 {
92 wxFSWPathType type = wxFSWPath_None;
93 if ( path.FileExists() )
94 {
95 type = wxFSWPath_File;
96 }
97 else if ( path.DirExists() )
98 {
99 type = wxFSWPath_Dir;
100 }
101 else
102 {
103 wxLogError(_("Can't monitor non-existent path \"%s\" for changes."),
104 path.GetFullPath());
105 return false;
106 }
107
108 return AddAny(path, events, type);
109 }
110
111 bool
112 wxFileSystemWatcherBase::AddAny(const wxFileName& path,
113 int events,
114 wxFSWPathType type,
115 const wxString& filespec)
116 {
117 wxString canonical = GetCanonicalPath(path);
118 if (canonical.IsEmpty())
119 return false;
120
121 // adding a path in a platform specific way
122 wxFSWatchInfo watch(canonical, events, type, filespec);
123 if ( !m_service->Add(watch) )
124 return false;
125
126 // on success, either add path to our 'watch-list'
127 // or, if already watched, inc the refcount. This may happen if
128 // a dir is Add()ed, then later AddTree() is called on a parent dir
129 wxFSWatchInfoMap::iterator it = m_watches.find(canonical);
130 if ( it == m_watches.end() )
131 {
132 wxFSWatchInfoMap::value_type val(canonical, watch);
133 m_watches.insert(val);
134 }
135 else
136 {
137 wxFSWatchInfo& watch = it->second;
138 int count = watch.IncRef();
139 wxLogTrace(wxTRACE_FSWATCHER,
140 "'%s' is now watched %d times", canonical, count);
141 }
142 return true;
143 }
144
145 bool wxFileSystemWatcherBase::Remove(const wxFileName& path)
146 {
147 // args validation & consistency checks
148 wxString canonical = GetCanonicalPath(path);
149 if (canonical.IsEmpty())
150 return false;
151
152 wxFSWatchInfoMap::iterator it = m_watches.find(canonical);
153 wxCHECK_MSG(it != m_watches.end(), false,
154 wxString::Format("Path '%s' is not watched", canonical));
155
156 // Decrement the watch's refcount and remove from watch-list if 0
157 bool ret = true;
158 wxFSWatchInfo& watch = it->second;
159 if ( !watch.DecRef() )
160 {
161 // remove in a platform specific way
162 ret = m_service->Remove(watch);
163
164 m_watches.erase(it);
165 }
166 return ret;
167 }
168
169 bool wxFileSystemWatcherBase::AddTree(const wxFileName& path, int events,
170 const wxString& filespec)
171 {
172 if (!path.DirExists())
173 return false;
174
175 // OPT could be optimised if we stored information about relationships
176 // between paths
177 class AddTraverser : public wxDirTraverser
178 {
179 public:
180 AddTraverser(wxFileSystemWatcherBase* watcher, int events,
181 const wxString& filespec) :
182 m_watcher(watcher), m_events(events), m_filespec(filespec)
183 {
184 }
185
186 virtual wxDirTraverseResult OnFile(const wxString& WXUNUSED(filename))
187 {
188 // There is no need to watch individual files as we watch the
189 // parent directory which will notify us about any changes in them.
190 return wxDIR_CONTINUE;
191 }
192
193 virtual wxDirTraverseResult OnDir(const wxString& dirname)
194 {
195 if ( m_watcher->AddAny(wxFileName::DirName(dirname),
196 m_events, wxFSWPath_Tree, m_filespec) )
197 {
198 wxLogTrace(wxTRACE_FSWATCHER,
199 "--- AddTree adding directory '%s' ---", dirname);
200 }
201 return wxDIR_CONTINUE;
202 }
203
204 private:
205 wxFileSystemWatcherBase* m_watcher;
206 int m_events;
207 wxString m_filespec;
208 };
209
210 wxDir dir(path.GetFullPath());
211 // Prevent asserts or infinite loops in trees containing symlinks
212 int flags = wxDIR_DIRS;
213 if ( !path.ShouldFollowLink() )
214 {
215 flags |= wxDIR_NO_FOLLOW;
216 }
217 AddTraverser traverser(this, events, filespec);
218 dir.Traverse(traverser, filespec, flags);
219
220 // Add the path itself explicitly as Traverse() doesn't return it.
221 AddAny(path.GetPathWithSep(), events, wxFSWPath_Tree, filespec);
222
223 return true;
224 }
225
226 bool wxFileSystemWatcherBase::RemoveTree(const wxFileName& path)
227 {
228 if (!path.DirExists())
229 return false;
230
231 // OPT could be optimised if we stored information about relationships
232 // between paths
233 class RemoveTraverser : public wxDirTraverser
234 {
235 public:
236 RemoveTraverser(wxFileSystemWatcherBase* watcher,
237 const wxString& filespec) :
238 m_watcher(watcher), m_filespec(filespec)
239 {
240 }
241
242 virtual wxDirTraverseResult OnFile(const wxString& WXUNUSED(filename))
243 {
244 // We never watch the individual files when watching the tree, so
245 // nothing to do here.
246 return wxDIR_CONTINUE;
247 }
248
249 virtual wxDirTraverseResult OnDir(const wxString& dirname)
250 {
251 m_watcher->Remove(wxFileName::DirName(dirname));
252 return wxDIR_CONTINUE;
253 }
254
255 private:
256 wxFileSystemWatcherBase* m_watcher;
257 wxString m_filespec;
258 };
259
260 // If AddTree() used a filespec, we must use the same one
261 wxString canonical = GetCanonicalPath(path);
262 wxFSWatchInfoMap::iterator it = m_watches.find(canonical);
263 wxCHECK_MSG( it != m_watches.end(), false,
264 wxString::Format("Path '%s' is not watched", canonical) );
265 wxFSWatchInfo watch = it->second;
266 const wxString filespec = watch.GetFilespec();
267
268 #if defined(__WINDOWS__)
269 // When there's no filespec, the wxMSW AddTree() would have set a watch
270 // on only the passed 'path'. We must therefore remove only this
271 if (filespec.empty())
272 {
273 return Remove(path);
274 }
275 // Otherwise fall through to the generic implementation
276 #endif // __WINDOWS__
277
278 wxDir dir(path.GetFullPath());
279 // AddTree() might have used the wxDIR_NO_FOLLOW to prevent asserts or
280 // infinite loops in trees containing symlinks. We need to do the same
281 // or we'll try to remove unwatched items. Let's hope the caller used
282 // the same ShouldFollowLink() setting as in AddTree()...
283 int flags = wxDIR_DIRS;
284 if ( !path.ShouldFollowLink() )
285 {
286 flags |= wxDIR_NO_FOLLOW;
287 }
288 RemoveTraverser traverser(this, filespec);
289 dir.Traverse(traverser, filespec, flags);
290
291 // As in AddTree() above, handle the path itself explicitly.
292 Remove(path);
293
294 return true;
295 }
296
297 bool wxFileSystemWatcherBase::RemoveAll()
298 {
299 m_service->RemoveAll();
300 m_watches.clear();
301 return true;
302 }
303
304 int wxFileSystemWatcherBase::GetWatchedPathsCount() const
305 {
306 return m_watches.size();
307 }
308
309 int wxFileSystemWatcherBase::GetWatchedPaths(wxArrayString* paths) const
310 {
311 wxCHECK_MSG( paths != NULL, -1, "Null array passed to retrieve paths");
312
313 wxFSWatchInfoMap::const_iterator it = m_watches.begin();
314 for ( ; it != m_watches.end(); ++it)
315 {
316 paths->push_back(it->first);
317 }
318
319 return m_watches.size();
320 }
321
322 #endif // wxUSE_FSWATCHER