• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

NepomukDaemons

filesystemwatcher.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE Project
00002    Copyright (c) 2008 Sebastian Trueg <trueg@kde.org>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License version 2 as published by the Free Software Foundation.
00007 
00008    This library is distributed in the hope that it will be useful,
00009    but WITHOUT ANY WARRANTY; without even the implied warranty of
00010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011    Library General Public License for more details.
00012 
00013    You should have received a copy of the GNU Library General Public License
00014    along with this library; see the file COPYING.LIB.  If not, write to
00015    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00016    Boston, MA 02110-1301, USA.
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     // small class to keep mem usage low
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         // wait for the next update or stop
00108         QMutex mutex;
00109         mutex.lock();
00110         if ( m_updateWaiter.wait( &mutex, interval*1000 ) ) {
00111             // canceled
00112             return;
00113         }
00114 
00115         // check all folders
00116         checkFolders();
00117 
00118         // check if we have been stopped
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         // check if anything changed in the folder
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         // check if any subfolder changed
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         // update in case folders have been created
00191         if ( dirty ) {
00192             updateChildrenCache( path, entry, true );
00193         }
00194     }
00195     // else -> FIXME: do we need to signal this or is it handled by the parent folder
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"

NepomukDaemons

Skip menu "NepomukDaemons"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • KCMShell
  • KNotify
  • KStyles
  • Nepomuk Daemons
Generated for API Reference by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal