Fix processing of events for MRU entries #10 and more in docview.
[wxWidgets.git] / src / common / fswatchercmn.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: 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 // args validation & consistency checks
83 if (!path.FileExists() && !path.DirExists())
84 return false;
85
86 wxString canonical = GetCanonicalPath(path);
87 if (canonical.IsEmpty())
88 return false;
89
90 wxCHECK_MSG(m_watches.find(canonical) == m_watches.end(), false,
91 wxString::Format("Path '%s' is already watched", canonical));
92
93 // adding a path in a platform specific way
94 wxFSWatchInfo watch(canonical, events);
95 if ( !m_service->Add(watch) )
96 return false;
97
98 // on success, add path to our 'watch-list'
99 wxFSWatchInfoMap::value_type val(canonical, watch);
100 return m_watches.insert(val).second;
101 }
102
103 bool wxFileSystemWatcherBase::Remove(const wxFileName& path)
104 {
105 // args validation & consistency checks
106 wxString canonical = GetCanonicalPath(path);
107 if (canonical.IsEmpty())
108 return false;
109
110 wxFSWatchInfoMap::iterator it = m_watches.find(canonical);
111 wxCHECK_MSG(it != m_watches.end(), false,
112 wxString::Format("Path '%s' is not watched", canonical));
113
114 // remove from watch-list
115 wxFSWatchInfo watch = it->second;
116 m_watches.erase(it);
117
118 // remove in a platform specific way
119 return m_service->Remove(watch);
120 }
121
122 bool wxFileSystemWatcherBase::AddTree(const wxFileName& path, int events,
123 const wxString& filter)
124 {
125 if (!path.DirExists())
126 return false;
127
128 // OPT could be optimised if we stored information about relationships
129 // between paths
130 class AddTraverser : public wxDirTraverser
131 {
132 public:
133 AddTraverser(wxFileSystemWatcherBase* watcher, int events) :
134 m_watcher(watcher), m_events(events)
135 {
136 }
137
138 // CHECK we choose which files to delegate to Add(), maybe we should pass
139 // all of them to Add() and let it choose? this is useful when adding a
140 // file to a dir that is already watched, then not only should we know
141 // about that, but Add() should also behave well then
142 virtual wxDirTraverseResult OnFile(const wxString& WXUNUSED(filename))
143 {
144 return wxDIR_CONTINUE;
145 }
146
147 virtual wxDirTraverseResult OnDir(const wxString& dirname)
148 {
149 wxLogTrace(wxTRACE_FSWATCHER, "--- AddTree adding '%s' ---",
150 dirname);
151 // we add as much as possible and ignore errors
152 m_watcher->Add(wxFileName(dirname), m_events);
153 return wxDIR_CONTINUE;
154 }
155
156 private:
157 wxFileSystemWatcherBase* m_watcher;
158 int m_events;
159 wxString m_filter;
160 };
161
162 wxDir dir(path.GetFullPath());
163 AddTraverser traverser(this, events);
164 dir.Traverse(traverser, filter);
165
166 return true;
167 }
168
169 bool wxFileSystemWatcherBase::RemoveTree(const wxFileName& path)
170 {
171 if (!path.DirExists())
172 return false;
173
174 // OPT could be optimised if we stored information about relationships
175 // between paths
176 class RemoveTraverser : public wxDirTraverser
177 {
178 public:
179 RemoveTraverser(wxFileSystemWatcherBase* watcher) :
180 m_watcher(watcher)
181 {
182 }
183
184 virtual wxDirTraverseResult OnFile(const wxString& filename)
185 {
186 m_watcher->Remove(wxFileName(filename));
187 return wxDIR_CONTINUE;
188 }
189
190 virtual wxDirTraverseResult OnDir(const wxString& dirname)
191 {
192 m_watcher->RemoveTree(wxFileName(dirname));
193 return wxDIR_CONTINUE;
194 }
195
196 private:
197 wxFileSystemWatcherBase* m_watcher;
198 };
199
200 wxDir dir(path.GetFullPath());
201 RemoveTraverser traverser(this);
202 dir.Traverse(traverser);
203
204 return true;
205 }
206
207 bool wxFileSystemWatcherBase::RemoveAll()
208 {
209 m_service->RemoveAll();
210 m_watches.clear();
211 return true;
212 }
213
214 int wxFileSystemWatcherBase::GetWatchedPathsCount() const
215 {
216 return m_watches.size();
217 }
218
219 int wxFileSystemWatcherBase::GetWatchedPaths(wxArrayString* paths) const
220 {
221 wxCHECK_MSG( paths != NULL, -1, "Null array passed to retrieve paths");
222
223 wxFSWatchInfoMap::const_iterator it = m_watches.begin();
224 for ( ; it != m_watches.end(); ++it)
225 {
226 paths->push_back(it->first);
227 }
228
229 return m_watches.size();
230 }
231
232 #endif // wxUSE_FSWATCHER