comparison src/fswatcher.h @ 548:dca5bd5b2a06

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