source: psi/trunk/src/tools/dirwatch/dirwatch_win.cpp

Last change on this file was 2, checked in by dmik, 19 years ago

Imported original Psi 0.10 sources from Affinix

File size: 5.0 KB
Line 
1/*
2 * dirwatch_unix.cpp - detect changes of directory content
3 * Copyright (C) 2003 Justin Karneges
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21#include"dirwatch.h"
22
23#include<qthread.h>
24#include<qptrlist.h>
25#include<qfile.h>
26#include<qdir.h>
27#include<qtimer.h>
28#include<windows.h>
29
30class DWEvent : public QEvent
31{
32public:
33 DWEvent(int _state)
34 :QEvent(QEvent::User)
35 {
36 state = _state;
37 }
38
39 int state;
40};
41
42class DWThread : public QThread
43{
44public:
45 DWThread(QObject *_par, HANDLE _h) : QThread()
46 {
47 par = _par;
48 h = _h;
49 }
50
51 void run()
52 {
53 while(WaitForSingleObject(h, INFINITE) == WAIT_OBJECT_0) {
54 // send a changed event
55 QThread::postEvent(par, new DWEvent(1));
56 if(!FindNextChangeNotification(h)) {
57 // send an error event
58 QThread::postEvent(par, new DWEvent(0));
59 return;
60 }
61 }
62 }
63
64 QObject *par;
65 HANDLE h;
66};
67
68class DWEntry : public QObject
69{
70 Q_OBJECT
71public:
72 static DWEntry * create(const QString &s)
73 {
74 HANDLE h = FindFirstChangeNotificationA(QFile::encodeName(QDir::convertSeparators(s)), TRUE,
75 FILE_NOTIFY_CHANGE_FILE_NAME |
76 FILE_NOTIFY_CHANGE_DIR_NAME |
77 FILE_NOTIFY_CHANGE_ATTRIBUTES |
78 FILE_NOTIFY_CHANGE_SIZE |
79 FILE_NOTIFY_CHANGE_LAST_WRITE |
80 FILE_NOTIFY_CHANGE_SECURITY);
81
82 if(h == INVALID_HANDLE_VALUE)
83 return 0;
84
85 DWEntry *e = new DWEntry;
86 e->dir = s;
87 e->h = h;
88 e->thread = new DWThread(e, h);
89 e->thread->start();
90 return e;
91 }
92
93 ~DWEntry()
94 {
95 if(thread) {
96 FindCloseChangeNotification(h);
97 thread->wait();
98 delete thread;
99 }
100 }
101
102signals:
103 void changed();
104
105protected:
106 bool event(QEvent *e)
107 {
108 if(e->type() == QEvent::User) {
109 DWEvent *de = (DWEvent *)e;
110 // error?
111 if(de->state == 0) {
112 thread->wait();
113 delete thread;
114 FindCloseChangeNotification(h);
115 thread = 0;
116 }
117 else {
118 dirty = true;
119 changed();
120 }
121
122 return true;
123 }
124 return false;
125 }
126
127public:
128 QString dir;
129 QValueList<int> idList;
130 bool dirty;
131
132private:
133 DWEntry()
134 {
135 dirty = false;
136 }
137
138 HANDLE h;
139 DWThread *thread;
140};
141
142class DirWatchPlatform::Private : public QObject
143{
144 Q_OBJECT
145public:
146 Private(DirWatchPlatform *_par)
147 {
148 par = _par;
149 list.setAutoDelete(true);
150 connect(&t, SIGNAL(timeout()), this, SLOT(slotNotify()));
151 }
152
153 ~Private()
154 {
155 list.clear();
156 }
157
158 QTimer t;
159 DirWatchPlatform *par;
160 QPtrList<DWEntry> list;
161
162 int addItem(const QString &s)
163 {
164 DWEntry *e = findEntryByDir(s);
165 if(!e) {
166 e = DWEntry::create(s);
167 if(!e)
168 return -1;
169 connect(e, SIGNAL(changed()), SLOT(slotChanged()));
170 list.append(e);
171 }
172 int id = getUniqueId();
173 e->idList.append(id);
174 return id;
175 }
176
177 void removeItem(int id)
178 {
179 DWEntry *e = findEntryById(id);
180 if(!e)
181 return;
182 e->idList.remove(id);
183 if(e->idList.isEmpty())
184 list.removeRef(e);
185 }
186
187 int getUniqueId()
188 {
189 for(int n = 0;; ++n) {
190 QPtrListIterator<DWEntry> it(list);
191 bool found = false;
192 for(DWEntry *e; (e = it.current()); ++it) {
193 for(QValueList<int>::ConstIterator idi = e->idList.begin(); idi != e->idList.end(); ++idi) {
194 if(*idi == n) {
195 found = true;
196 break;
197 }
198 }
199 if(found)
200 break;
201 }
202 if(!found)
203 return n;
204 }
205 }
206
207 DWEntry * findEntryByDir(const QString &s)
208 {
209 QPtrListIterator<DWEntry> it(list);
210 for(DWEntry *e; (e = it.current()); ++it) {
211 if(e->dir == s)
212 return e;
213 }
214 return 0;
215 }
216
217 DWEntry * findEntryById(int id)
218 {
219 QPtrListIterator<DWEntry> it(list);
220 for(DWEntry *e; (e = it.current()); ++it) {
221 for(QValueList<int>::ConstIterator idi = e->idList.begin(); idi != e->idList.end(); ++idi) {
222 if(*idi == id)
223 return e;
224 }
225 }
226 return 0;
227 }
228
229private slots:
230 void slotChanged()
231 {
232 // use a timer to combine multiple changed events into one
233 if(!t.isActive())
234 t.start(200, true);
235 }
236
237 void slotNotify()
238 {
239 // see who is dirty
240 QPtrListIterator<DWEntry> it(list);
241 for(DWEntry *e; (e = it.current()); ++it) {
242 if(e->dirty) {
243 e->dirty = false;
244 for(QValueList<int>::ConstIterator idi = e->idList.begin(); idi != e->idList.end(); ++idi) {
245 par->triggerDirChanged(*idi);
246 }
247 }
248 }
249 }
250};
251
252DirWatchPlatform::DirWatchPlatform()
253:QObject(0)
254{
255 d = new Private(this);
256}
257
258DirWatchPlatform::~DirWatchPlatform()
259{
260 delete d;
261}
262
263bool DirWatchPlatform::init()
264{
265 return true;
266}
267
268int DirWatchPlatform::addDir(const QString &s)
269{
270 return d->addItem(s);
271}
272
273void DirWatchPlatform::removeDir(int id)
274{
275 d->removeItem(id);
276}
277
278#include"dirwatch_win.moc"
Note: See TracBrowser for help on using the repository browser.