Chris@538
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@538
|
2
|
Chris@538
|
3 /*
|
Chris@538
|
4 EasyMercurial
|
Chris@538
|
5
|
Chris@538
|
6 Based on HgExplorer by Jari Korhonen
|
Chris@538
|
7 Copyright (c) 2010 Jari Korhonen
|
Chris@560
|
8 Copyright (c) 2012 Chris Cannam
|
Chris@560
|
9 Copyright (c) 2012 Queen Mary, University of London
|
Chris@538
|
10
|
Chris@538
|
11 This program is free software; you can redistribute it and/or
|
Chris@538
|
12 modify it under the terms of the GNU General Public License as
|
Chris@538
|
13 published by the Free Software Foundation; either version 2 of the
|
Chris@538
|
14 License, or (at your option) any later version. See the file
|
Chris@538
|
15 COPYING included with this distribution for more information.
|
Chris@538
|
16 */
|
Chris@538
|
17
|
Chris@538
|
18 #ifndef FSWATCHER_H
|
Chris@538
|
19 #define FSWATCHER_H
|
Chris@538
|
20
|
Chris@538
|
21 #include <QObject>
|
Chris@538
|
22 #include <QMutex>
|
Chris@538
|
23 #include <QString>
|
Chris@538
|
24 #include <QSet>
|
Chris@538
|
25 #include <QHash>
|
Chris@538
|
26 #include <QMap>
|
Chris@586
|
27 #include <QDateTime>
|
Chris@538
|
28 #include <QStringList>
|
Chris@584
|
29
|
Chris@584
|
30 #ifndef Q_OS_MAC
|
Chris@584
|
31 // We don't use QFileSystemWatcher on OS/X.
|
Chris@584
|
32 // See comments at top of fswatcher.cpp for an explanation.
|
Chris@538
|
33 #include <QFileSystemWatcher>
|
Chris@584
|
34 #endif
|
Chris@538
|
35
|
Chris@538
|
36 class FsWatcher : public QObject
|
Chris@538
|
37 {
|
Chris@538
|
38 Q_OBJECT
|
Chris@538
|
39
|
Chris@538
|
40 public:
|
Chris@538
|
41 FsWatcher();
|
Chris@538
|
42 virtual ~FsWatcher();
|
Chris@538
|
43
|
Chris@538
|
44 /**
|
Chris@539
|
45 * Set the root path of the work directory to be monitored. This
|
Chris@539
|
46 * directory and all its subdirectories (recursively) will be
|
Chris@539
|
47 * monitored for changes.
|
Chris@539
|
48 *
|
Chris@541
|
49 * If this path differs from the currently set work dir path, then
|
Chris@541
|
50 * the tracked file paths will also be cleared. Call
|
Chris@539
|
51 * setTrackedFilePaths afterwards to ensure non-directory files
|
Chris@539
|
52 * are monitored.
|
Chris@538
|
53 */
|
Chris@538
|
54 void setWorkDirPath(QString path);
|
Chris@538
|
55
|
Chris@538
|
56 /**
|
Chris@539
|
57 * Provide a set of paths for files which should be tracked. These
|
Chris@542
|
58 * will be the only non-directory files monitored for changes. The
|
Chris@542
|
59 * paths should be relative to the work directory.
|
Chris@539
|
60 */
|
Chris@539
|
61 void setTrackedFilePaths(QStringList paths);
|
Chris@539
|
62
|
Chris@539
|
63 /**
|
Chris@538
|
64 * Provide a set of prefixes to ignore. Files whose names start
|
Chris@538
|
65 * with a prefix in this set will be ignored when they change.
|
Chris@538
|
66 */
|
Chris@538
|
67 void setIgnoredFilePrefixes(QStringList prefixes);
|
Chris@538
|
68
|
Chris@538
|
69 /**
|
Chris@538
|
70 * Provide a set of suffixes to ignore. Files whose names end
|
Chris@538
|
71 * with a suffix in this set will be ignored when they change.
|
Chris@538
|
72 */
|
Chris@538
|
73 void setIgnoredFileSuffixes(QStringList suffixes);
|
Chris@538
|
74
|
Chris@538
|
75 /**
|
Chris@538
|
76 * Return a token to identify the current caller in subsequent
|
Chris@538
|
77 * calls to getChangedPaths(). Only changes that occur after this
|
Chris@538
|
78 * has been called can be detected by the caller.
|
Chris@538
|
79 */
|
Chris@538
|
80 int getNewToken();
|
Chris@538
|
81
|
Chris@538
|
82 /**
|
Chris@538
|
83 * Return a list of all non-ignored file paths that have been
|
Chris@538
|
84 * observed to have changed since the last call to getChangedPaths
|
Chris@538
|
85 * with the same token.
|
Chris@538
|
86 */
|
Chris@538
|
87 QSet<QString> getChangedPaths(int token);
|
Chris@538
|
88
|
Chris@538
|
89 signals:
|
Chris@538
|
90 /**
|
Chris@538
|
91 * Emitted when something has changed. Use the asynchronous
|
Chris@538
|
92 * interface to find out what.
|
Chris@538
|
93 */
|
Chris@538
|
94 void changed();
|
Chris@538
|
95
|
Chris@585
|
96 public slots:
|
Chris@538
|
97 void fsDirectoryChanged(QString);
|
Chris@538
|
98 void fsFileChanged(QString);
|
Chris@538
|
99
|
Chris@538
|
100 private:
|
Chris@538
|
101 // call with lock already held
|
Chris@584
|
102 void clearWatchedPaths();
|
Chris@584
|
103
|
Chris@584
|
104 // call with lock already held
|
Chris@538
|
105 void addWorkDirectory(QString path);
|
Chris@538
|
106
|
Chris@538
|
107 // call with lock already held
|
Chris@538
|
108 bool shouldIgnore(QString path);
|
Chris@538
|
109
|
Chris@540
|
110 // call with lock already held. Returns set of non-ignored files in dir
|
Chris@540
|
111 QSet<QString> scanDirectory(QString path);
|
Chris@540
|
112
|
Chris@540
|
113 // call with lock already held
|
Chris@540
|
114 void debugPrint();
|
Chris@540
|
115
|
Chris@538
|
116 private:
|
Chris@538
|
117 /**
|
Chris@538
|
118 * A change associates a filename with a counter (the
|
Chris@538
|
119 * size_t). Each time a file is changed, its counter is assigned
|
Chris@538
|
120 * from m_lastCounter and m_lastCounter is incremented.
|
Chris@538
|
121 *
|
Chris@538
|
122 * This is not especially efficient -- we often want to find "all
|
Chris@538
|
123 * files whose counter is greater than X" which involves a
|
Chris@538
|
124 * traversal. Maybe something better later.
|
Chris@538
|
125 */
|
Chris@538
|
126 QHash<QString, size_t> m_changes;
|
Chris@538
|
127
|
Chris@538
|
128 /**
|
Chris@538
|
129 * Associates a token (the client identifier) with a counter. The
|
Chris@538
|
130 * counter represents the value of m_lastCounter at the moment
|
Chris@538
|
131 * getChangedPaths last completed for that token. Any files in
|
Chris@538
|
132 * m_changes whose counters are larger must have been modified.
|
Chris@538
|
133 */
|
Chris@538
|
134 QMap<int, size_t> m_tokenMap;
|
Chris@538
|
135
|
Chris@540
|
136 /**
|
Chris@540
|
137 * Associates a directory path with a list of all the files in it
|
Chris@540
|
138 * that do not match our ignore patterns. When a directory is
|
Chris@540
|
139 * signalled as having changed, then we need to rescan it and
|
Chris@540
|
140 * compare against this list before we can determine whether to
|
Chris@540
|
141 * notify about the change or not.
|
Chris@540
|
142 */
|
Chris@540
|
143 QHash<QString, QSet<QString> > m_dirContents;
|
Chris@540
|
144
|
Chris@538
|
145 QStringList m_ignoredPrefixes;
|
Chris@538
|
146 QStringList m_ignoredSuffixes;
|
Chris@538
|
147
|
Chris@538
|
148 /// Everything in this class is synchronised.
|
Chris@538
|
149 QMutex m_mutex;
|
Chris@538
|
150
|
Chris@538
|
151 QString m_workDirPath;
|
Chris@538
|
152 int m_lastToken;
|
Chris@538
|
153 size_t m_lastCounter;
|
Chris@584
|
154
|
Chris@584
|
155 #ifdef Q_OS_MAC
|
Chris@584
|
156 void *m_stream;
|
Chris@586
|
157 typedef QMap<QString, QDateTime> PathTimeMap;
|
Chris@586
|
158 PathTimeMap m_trackedFileUpdates;
|
Chris@586
|
159 bool manuallyCheckTrackedFiles();
|
Chris@584
|
160 #else
|
Chris@538
|
161 QFileSystemWatcher m_watcher;
|
Chris@584
|
162 #endif
|
Chris@538
|
163 };
|
Chris@538
|
164
|
Chris@538
|
165 #endif
|