annotate src/fswatcher.h @ 593:40b40c193eaa

Fix file update time calculation in FS watcher
author Chris Cannam
date Tue, 17 Apr 2012 13:31:30 +0100
parents 687d9e700e81
children ae67ea0af696
rev   line source
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