]> git.saurik.com Git - wxWidgets.git/blob - src/common/fswatchercmn.cpp
Merge in from trunk r64802 - r68625
[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& WXUNUSED(filename))
163 {
164 return wxDIR_CONTINUE;
165 }
166
167 virtual wxDirTraverseResult OnDir(const wxString& dirname)
168 {
169 wxLogTrace(wxTRACE_FSWATCHER, "--- AddTree adding '%s' ---",
170 dirname);
171 // we add as much as possible and ignore errors
172 m_watcher->Add(wxFileName(dirname), m_events);
173 return wxDIR_CONTINUE;
174 }
175
176 private:
177 wxFileSystemWatcherBase* m_watcher;
178 int m_events;
179 wxString m_filter;
180 };
181
182 wxDir dir(path.GetFullPath());
183 AddTraverser traverser(this, events);
184 dir.Traverse(traverser, filter);
185
186 return true;
187 }
188
189 bool wxFileSystemWatcherBase::RemoveTree(const wxFileName& path)
190 {
191 if (!path.DirExists())
192 return false;
193
194 // OPT could be optimised if we stored information about relationships
195 // between paths
196 class RemoveTraverser : public wxDirTraverser
197 {
198 public:
199 RemoveTraverser(wxFileSystemWatcherBase* watcher) :
200 m_watcher(watcher)
201 {
202 }
203
204 virtual wxDirTraverseResult OnFile(const wxString& filename)
205 {
206 m_watcher->Remove(wxFileName(filename));
207 return wxDIR_CONTINUE;
208 }
209
210 virtual wxDirTraverseResult OnDir(const wxString& dirname)
211 {
212 m_watcher->RemoveTree(wxFileName(dirname));
213 return wxDIR_CONTINUE;
214 }
215
216 private:
217 wxFileSystemWatcherBase* m_watcher;
218 };
219
220 wxDir dir(path.GetFullPath());
221 RemoveTraverser traverser(this);
222 dir.Traverse(traverser);
223
224 return true;
225 }
226
227 bool wxFileSystemWatcherBase::RemoveAll()
228 {
229 m_service->RemoveAll();
230 m_watches.clear();
231 return true;
232 }
233
234 int wxFileSystemWatcherBase::GetWatchedPathsCount() const
235 {
236 return m_watches.size();
237 }
238
239 int wxFileSystemWatcherBase::GetWatchedPaths(wxArrayString* paths) const
240 {
241 wxCHECK_MSG( paths != NULL, -1, "Null array passed to retrieve paths");
242
243 wxFSWatchInfoMap::const_iterator it = m_watches.begin();
244 for ( ; it != m_watches.end(); ++it)
245 {
246 paths->push_back(it->first);
247 }
248
249 return m_watches.size();
250 }
251
252 #endif // wxUSE_FSWATCHER