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>
36 // small class to keep mem usage low
48 QHash
<QString
, FolderEntry
> children
;
52 class FileSystemWatcher::Private
: public QThread
55 Private( FileSystemWatcher
* parent
)
62 QHash
<QString
, FolderEntry
> cache
;
66 void start( const QDateTime
& startTime
);
70 void buildFolderCache( uint mTime
);
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
;
86 void FileSystemWatcher::Private::start( const QDateTime
& startTime
)
89 m_startTime
= startTime
;
94 void FileSystemWatcher::Private::stop()
96 QMutexLocker
lock( &m_stoppedMutex
);
98 m_updateWaiter
.wakeAll();
102 void FileSystemWatcher::Private::run()
104 buildFolderCache( m_startTime
.toTime_t() );
107 // wait for the next update or stop
110 if ( m_updateWaiter
.wait( &mutex
, interval
*1000 ) ) {
118 // check if we have been stopped
119 QMutexLocker
lock( &m_stoppedMutex
);
126 void FileSystemWatcher::Private::buildFolderCache( uint mTime
)
130 foreach( QString folder
, folders
) {
131 if ( folder
.endsWith( '/' ) )
132 folder
.truncate( folder
.length()-1 );
133 FolderEntry
entry( mTime
);
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() ) {
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
178 if ( info
.lastModified().toTime_t() > entry
.mTime
) {
179 entry
.mTime
= info
.lastModified().toTime_t();
180 emit q
->dirty( path
);
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
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
)
201 d( new Private( this ) )
206 FileSystemWatcher::~FileSystemWatcher()
213 void FileSystemWatcher::start( const QDateTime
& startTime
)
216 d
->start( startTime
);
220 void FileSystemWatcher::stop()
227 QStringList
FileSystemWatcher::folders() const
233 bool FileSystemWatcher::watchRecursively() const
239 int FileSystemWatcher::interval() const
245 void FileSystemWatcher::setFolders( const QStringList
& folders
)
247 d
->folders
= folders
;
251 void FileSystemWatcher::setWatchRecursively( bool r
)
257 void FileSystemWatcher::setInterval( int seconds
)
259 d
->interval
= seconds
;
262 #include "filesystemwatcher.moc"