delay a few things on startup, such as setting the visibility mode, which ensures...
[personal-kdebase.git] / runtime / nepomuk / services / strigi / filesystemwatcher.cpp
blobcac52e506460b4995c68467f8c5244b6c7bb8795
1 /* This file is part of the KDE Project
2 Copyright (c) 2008 Sebastian Trueg <trueg@kde.org>
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License version 2 as published by the Free Software Foundation.
8 This library is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 Library General Public License for more details.
13 You should have received a copy of the GNU Library General Public License
14 along with this library; see the file COPYING.LIB. If not, write to
15 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 Boston, MA 02110-1301, USA.
19 #include "filesystemwatcher.h"
21 #include <QtCore/QTimer>
22 #include <QtCore/QHash>
23 #include <QtCore/QDateTime>
24 #include <QtCore/QStringList>
25 #include <QtCore/QDirIterator>
26 #include <QtCore/QFileInfo>
27 #include <QtCore/QThread>
28 #include <QtCore/QWaitCondition>
29 #include <QtCore/QMutex>
30 #include <QtCore/QMutexLocker>
32 #include <KDebug>
35 namespace {
36 // small class to keep mem usage low
37 class FolderEntry
39 public:
40 FolderEntry() {
43 FolderEntry( int m )
44 : mTime( m ) {
47 uint mTime;
48 QHash<QString, FolderEntry> children;
52 class FileSystemWatcher::Private : public QThread
54 public:
55 Private( FileSystemWatcher* parent )
56 : recursive( true ),
57 interval( 10*60 ),
58 q( parent ) {
61 QStringList folders;
62 QHash<QString, FolderEntry> cache;
63 bool recursive;
64 int interval;
66 void start( const QDateTime& startTime );
67 void stop();
68 void run();
70 void buildFolderCache( uint mTime );
71 void checkFolders();
73 private:
74 void updateChildrenCache( const QString& parentPath, FolderEntry& parentEntry, bool signalNewEntries );
75 void checkFolder( const QString& path, FolderEntry& folder );
77 QDateTime m_startTime;
78 QWaitCondition m_updateWaiter;
79 QMutex m_stoppedMutex;
80 bool m_stopped;
82 FileSystemWatcher* q;
86 void FileSystemWatcher::Private::start( const QDateTime& startTime )
88 m_stopped = false;
89 m_startTime = startTime;
90 QThread::start();
94 void FileSystemWatcher::Private::stop()
96 QMutexLocker lock( &m_stoppedMutex );
97 m_stopped = true;
98 m_updateWaiter.wakeAll();
102 void FileSystemWatcher::Private::run()
104 buildFolderCache( m_startTime.toTime_t() );
106 while ( 1 ) {
107 // wait for the next update or stop
108 QMutex mutex;
109 mutex.lock();
110 if ( m_updateWaiter.wait( &mutex, interval*1000 ) ) {
111 // canceled
112 return;
115 // check all folders
116 checkFolders();
118 // check if we have been stopped
119 QMutexLocker lock( &m_stoppedMutex );
120 if ( m_stopped )
121 return;
126 void FileSystemWatcher::Private::buildFolderCache( uint mTime )
128 cache.clear();
130 foreach( QString folder, folders ) {
131 if ( folder.endsWith( '/' ) )
132 folder.truncate( folder.length()-1 );
133 FolderEntry entry( mTime );
134 if ( recursive ) {
135 updateChildrenCache( folder, entry, false );
137 cache.insert( folder, entry );
142 void FileSystemWatcher::Private::updateChildrenCache( const QString& parentPath, FolderEntry& parentEntry, bool signalNewEntries )
144 QDirIterator dirIt( parentPath, QDir::NoDotAndDotDot|QDir::Readable|QDir::Dirs|QDir::NoSymLinks );
145 while ( dirIt.hasNext() ) {
146 dirIt.next();
147 if ( !parentEntry.children.contains( dirIt.fileName() ) ) {
148 FolderEntry entry( parentEntry.mTime );
149 parentEntry.children.insert( dirIt.fileName(), entry );
150 if ( signalNewEntries ) {
151 emit q->dirty( dirIt.filePath() );
156 for( QHash<QString, FolderEntry>::iterator it = parentEntry.children.begin();
157 it != parentEntry.children.end(); ++it ) {
158 updateChildrenCache( parentPath + '/' + it.key(), it.value(), signalNewEntries );
163 void FileSystemWatcher::Private::checkFolders()
165 for( QHash<QString, FolderEntry>::iterator it = cache.begin();
166 it != cache.end(); ++it ) {
167 checkFolder( it.key(), it.value() );
172 void FileSystemWatcher::Private::checkFolder( const QString& path, FolderEntry& entry )
174 QFileInfo info( path );
175 if ( info.exists() ) {
176 // check if anything changed in the folder
177 bool dirty = false;
178 if ( info.lastModified().toTime_t() > entry.mTime ) {
179 entry.mTime = info.lastModified().toTime_t();
180 emit q->dirty( path );
181 dirty = true;
184 // check if any subfolder changed
185 for( QHash<QString, FolderEntry>::iterator it = entry.children.begin();
186 it != entry.children.end(); ++it ) {
187 checkFolder( path + '/' + it.key(), it.value() );
190 // update in case folders have been created
191 if ( dirty ) {
192 updateChildrenCache( path, entry, true );
195 // else -> FIXME: do we need to signal this or is it handled by the parent folder
199 FileSystemWatcher::FileSystemWatcher( QObject* parent )
200 : QObject( parent ),
201 d( new Private( this ) )
206 FileSystemWatcher::~FileSystemWatcher()
208 stop();
209 delete d;
213 void FileSystemWatcher::start( const QDateTime& startTime )
215 stop();
216 d->start( startTime );
220 void FileSystemWatcher::stop()
222 d->stop();
223 d->wait();
227 QStringList FileSystemWatcher::folders() const
229 return d->folders;
233 bool FileSystemWatcher::watchRecursively() const
235 return d->recursive;
239 int FileSystemWatcher::interval() const
241 return d->interval;
245 void FileSystemWatcher::setFolders( const QStringList& folders )
247 d->folders = folders;
251 void FileSystemWatcher::setWatchRecursively( bool r )
253 d->recursive = r;
257 void FileSystemWatcher::setInterval( int seconds )
259 d->interval = seconds;
262 #include "filesystemwatcher.moc"