NepomukDaemons
filesystemwatcher.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "filesystemwatcher.h"
00020
00021 #include <QtCore/QTimer>
00022 #include <QtCore/QHash>
00023 #include <QtCore/QDateTime>
00024 #include <QtCore/QStringList>
00025 #include <QtCore/QDirIterator>
00026 #include <QtCore/QFileInfo>
00027 #include <QtCore/QThread>
00028 #include <QtCore/QWaitCondition>
00029 #include <QtCore/QMutex>
00030 #include <QtCore/QMutexLocker>
00031
00032 #include <KDebug>
00033
00034
00035 namespace {
00036
00037 class FolderEntry
00038 {
00039 public:
00040 FolderEntry() {
00041 }
00042
00043 FolderEntry( int m )
00044 : mTime( m ) {
00045 }
00046
00047 uint mTime;
00048 QHash<QString, FolderEntry> children;
00049 };
00050 }
00051
00052 class FileSystemWatcher::Private : public QThread
00053 {
00054 public:
00055 Private( FileSystemWatcher* parent )
00056 : recursive( true ),
00057 interval( 10*60 ),
00058 q( parent ) {
00059 }
00060
00061 QStringList folders;
00062 QHash<QString, FolderEntry> cache;
00063 bool recursive;
00064 int interval;
00065
00066 void start( const QDateTime& startTime );
00067 void stop();
00068 void run();
00069
00070 void buildFolderCache( uint mTime );
00071 void checkFolders();
00072
00073 private:
00074 void updateChildrenCache( const QString& parentPath, FolderEntry& parentEntry, bool signalNewEntries );
00075 void checkFolder( const QString& path, FolderEntry& folder );
00076
00077 QDateTime m_startTime;
00078 QWaitCondition m_updateWaiter;
00079 QMutex m_stoppedMutex;
00080 bool m_stopped;
00081
00082 FileSystemWatcher* q;
00083 };
00084
00085
00086 void FileSystemWatcher::Private::start( const QDateTime& startTime )
00087 {
00088 m_stopped = false;
00089 m_startTime = startTime;
00090 QThread::start();
00091 }
00092
00093
00094 void FileSystemWatcher::Private::stop()
00095 {
00096 QMutexLocker lock( &m_stoppedMutex );
00097 m_stopped = true;
00098 m_updateWaiter.wakeAll();
00099 }
00100
00101
00102 void FileSystemWatcher::Private::run()
00103 {
00104 buildFolderCache( m_startTime.toTime_t() );
00105
00106 while ( 1 ) {
00107
00108 QMutex mutex;
00109 mutex.lock();
00110 if ( m_updateWaiter.wait( &mutex, interval*1000 ) ) {
00111
00112 return;
00113 }
00114
00115
00116 checkFolders();
00117
00118
00119 QMutexLocker lock( &m_stoppedMutex );
00120 if ( m_stopped )
00121 return;
00122 }
00123 }
00124
00125
00126 void FileSystemWatcher::Private::buildFolderCache( uint mTime )
00127 {
00128 cache.clear();
00129
00130 foreach( QString folder, folders ) {
00131 if ( folder.endsWith( '/' ) )
00132 folder.truncate( folder.length()-1 );
00133 FolderEntry entry( mTime );
00134 if ( recursive ) {
00135 updateChildrenCache( folder, entry, false );
00136 }
00137 cache.insert( folder, entry );
00138 }
00139 }
00140
00141
00142 void FileSystemWatcher::Private::updateChildrenCache( const QString& parentPath, FolderEntry& parentEntry, bool signalNewEntries )
00143 {
00144 QDirIterator dirIt( parentPath, QDir::NoDotAndDotDot|QDir::Readable|QDir::Dirs|QDir::NoSymLinks );
00145 while ( dirIt.hasNext() ) {
00146 dirIt.next();
00147 if ( !parentEntry.children.contains( dirIt.fileName() ) ) {
00148 FolderEntry entry( parentEntry.mTime );
00149 parentEntry.children.insert( dirIt.fileName(), entry );
00150 if ( signalNewEntries ) {
00151 emit q->dirty( dirIt.filePath() );
00152 }
00153 }
00154 }
00155
00156 for( QHash<QString, FolderEntry>::iterator it = parentEntry.children.begin();
00157 it != parentEntry.children.end(); ++it ) {
00158 updateChildrenCache( parentPath + '/' + it.key(), it.value(), signalNewEntries );
00159 }
00160 }
00161
00162
00163 void FileSystemWatcher::Private::checkFolders()
00164 {
00165 for( QHash<QString, FolderEntry>::iterator it = cache.begin();
00166 it != cache.end(); ++it ) {
00167 checkFolder( it.key(), it.value() );
00168 }
00169 }
00170
00171
00172 void FileSystemWatcher::Private::checkFolder( const QString& path, FolderEntry& entry )
00173 {
00174 QFileInfo info( path );
00175 if ( info.exists() ) {
00176
00177 bool dirty = false;
00178 if ( info.lastModified().toTime_t() > entry.mTime ) {
00179 entry.mTime = info.lastModified().toTime_t();
00180 emit q->dirty( path );
00181 dirty = true;
00182 }
00183
00184
00185 for( QHash<QString, FolderEntry>::iterator it = entry.children.begin();
00186 it != entry.children.end(); ++it ) {
00187 checkFolder( path + '/' + it.key(), it.value() );
00188 }
00189
00190
00191 if ( dirty ) {
00192 updateChildrenCache( path, entry, true );
00193 }
00194 }
00195
00196 }
00197
00198
00199 FileSystemWatcher::FileSystemWatcher( QObject* parent )
00200 : QObject( parent ),
00201 d( new Private( this ) )
00202 {
00203 }
00204
00205
00206 FileSystemWatcher::~FileSystemWatcher()
00207 {
00208 stop();
00209 delete d;
00210 }
00211
00212
00213 void FileSystemWatcher::start( const QDateTime& startTime )
00214 {
00215 stop();
00216 d->start( startTime );
00217 }
00218
00219
00220 void FileSystemWatcher::stop()
00221 {
00222 d->stop();
00223 d->wait();
00224 }
00225
00226
00227 QStringList FileSystemWatcher::folders() const
00228 {
00229 return d->folders;
00230 }
00231
00232
00233 bool FileSystemWatcher::watchRecursively() const
00234 {
00235 return d->recursive;
00236 }
00237
00238
00239 int FileSystemWatcher::interval() const
00240 {
00241 return d->interval;
00242 }
00243
00244
00245 void FileSystemWatcher::setFolders( const QStringList& folders )
00246 {
00247 d->folders = folders;
00248 }
00249
00250
00251 void FileSystemWatcher::setWatchRecursively( bool r )
00252 {
00253 d->recursive = r;
00254 }
00255
00256
00257 void FileSystemWatcher::setInterval( int seconds )
00258 {
00259 d->interval = seconds;
00260 }
00261
00262 #include "filesystemwatcher.moc"