File indexing completed on 2024-05-05 04:48:50
0001 /**************************************************************************************** 0002 * Copyright (c) 2010-2013 Ralf Engels <ralf-engels@gmx.de> * 0003 * * 0004 * This program is free software; you can redistribute it and/or modify it under * 0005 * the terms of the GNU General Public License as published by the Free Software * 0006 * Foundation; either version 2 of the License, or (at your option) any later * 0007 * version. * 0008 * * 0009 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0010 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0011 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0012 * * 0013 * You should have received a copy of the GNU General Public License along with * 0014 * this program. If not, see <http://www.gnu.org/licenses/>. * 0015 ****************************************************************************************/ 0016 0017 #define DEBUG_PREFIX "AbstractDirectoryWatcher" 0018 0019 #include "AbstractDirectoryWatcher.h" 0020 0021 #include "amarokconfig.h" 0022 #include "core/support/Debug.h" 0023 0024 #include <KDirWatch> 0025 0026 #include <QTimer> 0027 #include <QFileInfo> 0028 #include <QMutexLocker> 0029 0030 static const int WATCH_INTERVAL = 60 * 1000; // = 60 seconds 0031 static const int DELAYED_SCAN_INTERVAL = 2 * 1000; // = 2 seconds 0032 0033 AbstractDirectoryWatcher::AbstractDirectoryWatcher() 0034 : QObject() 0035 , ThreadWeaver::Job() 0036 , m_delayedScanTimer( nullptr ) 0037 , m_watcher( nullptr ) 0038 , m_aborted( false ) 0039 , m_blocked( false ) 0040 { 0041 m_delayedScanTimer = new QTimer( this ); 0042 m_delayedScanTimer->setSingleShot( true ); 0043 connect( m_delayedScanTimer, &QTimer::timeout, this, &AbstractDirectoryWatcher::delayTimeout ); 0044 0045 // -- create a new watcher 0046 m_watcher = new KDirWatch( this ); 0047 0048 connect( m_watcher, &KDirWatch::dirty, 0049 this, &AbstractDirectoryWatcher::delayedScan ); 0050 connect( m_watcher, &KDirWatch::created, 0051 this, &AbstractDirectoryWatcher::delayedScan ); 0052 connect( m_watcher, &KDirWatch::deleted, 0053 this, &AbstractDirectoryWatcher::delayedScan ); 0054 0055 m_watcher->startScan( false ); 0056 } 0057 0058 void 0059 AbstractDirectoryWatcher::run(ThreadWeaver::JobPointer self, ThreadWeaver::Thread *thread) 0060 { 0061 Q_UNUSED(self); 0062 Q_UNUSED(thread); 0063 0064 // TODO: re-create the watcher if scanRecursively has changed 0065 QSet<QString> oldWatchDirs; 0066 0067 forever { 0068 m_mutex.lock(); 0069 m_waitCondition.wait( &m_mutex, WATCH_INTERVAL ); 0070 0071 if( m_aborted ) 0072 break; 0073 0074 // -- start scan 0075 if( AmarokConfig::monitorChanges() ) 0076 { 0077 if( m_watcher->isStopped() ) 0078 { 0079 // Check if directories changed while we didn't have a watcher 0080 QList<QUrl> urls; 0081 foreach( const QString &path, collectionFolders() ) 0082 { 0083 urls.append( QUrl::fromLocalFile( path ) ); 0084 } 0085 Q_EMIT requestScan( urls, GenericScanManager::PartialUpdateScan ); 0086 m_watcher->startScan( true ); 0087 } 0088 0089 0090 // -- update the KDirWatch with the current set of directories 0091 const QStringList colFolders=collectionFolders(); 0092 QSet<QString> dirs(colFolders.begin(), colFolders.end()); 0093 0094 // - add new 0095 QSet<QString> newDirs = dirs - oldWatchDirs; 0096 foreach( const QString& dir, newDirs ) 0097 { 0098 m_watcher->addDir( dir, 0099 AmarokConfig::scanRecursively() ? 0100 KDirWatch::WatchSubDirs : KDirWatch::WatchDirOnly ); 0101 } 0102 0103 // - remove old 0104 QSet<QString> removeDirs = oldWatchDirs - dirs; 0105 foreach( const QString& dir, removeDirs ) 0106 { 0107 m_watcher->removeDir( dir ); 0108 } 0109 0110 oldWatchDirs = dirs; 0111 0112 } 0113 else 0114 { 0115 if( !m_watcher->isStopped() ) 0116 m_watcher->stopScan(); 0117 } 0118 0119 m_mutex.unlock(); 0120 } 0121 0122 } 0123 0124 void 0125 AbstractDirectoryWatcher::defaultBegin(const ThreadWeaver::JobPointer& self, ThreadWeaver::Thread *thread) 0126 { 0127 Q_EMIT started(self); 0128 ThreadWeaver::Job::defaultBegin(self, thread); 0129 } 0130 0131 void 0132 AbstractDirectoryWatcher::defaultEnd(const ThreadWeaver::JobPointer& self, ThreadWeaver::Thread *thread) 0133 { 0134 ThreadWeaver::Job::defaultEnd(self, thread); 0135 if (!self->success()) { 0136 Q_EMIT failed(self); 0137 } 0138 Q_EMIT done(self); 0139 } 0140 0141 void 0142 AbstractDirectoryWatcher::requestAbort() 0143 { 0144 DEBUG_BLOCK 0145 0146 m_aborted = true; 0147 m_waitCondition.wakeAll(); 0148 } 0149 0150 void 0151 AbstractDirectoryWatcher::setBlockScanning( bool block ) 0152 { 0153 m_blocked = block; 0154 0155 // send out the old requests 0156 if( !m_blocked ) 0157 delayTimeout(); 0158 } 0159 0160 void 0161 AbstractDirectoryWatcher::delayTimeout() 0162 { 0163 QMutexLocker locker( &m_dirsMutex ); 0164 0165 if( m_blocked || m_aborted ) 0166 return; 0167 0168 if( m_scanDirsRequested.isEmpty() ) 0169 return; 0170 0171 Q_EMIT requestScan( m_scanDirsRequested.values(), GenericScanManager::PartialUpdateScan ); 0172 m_scanDirsRequested.clear(); 0173 } 0174 0175 void 0176 AbstractDirectoryWatcher::delayedScan( const QString &path ) 0177 { 0178 QFileInfo info( path ); 0179 if( info.isDir() ) 0180 addDirToList( path ); 0181 else 0182 addDirToList( info.path() ); 0183 0184 m_delayedScanTimer->start( DELAYED_SCAN_INTERVAL ); 0185 } 0186 0187 void 0188 AbstractDirectoryWatcher::addDirToList( const QString &directory ) 0189 { 0190 QMutexLocker locker( &m_dirsMutex ); 0191 0192 debug() << "addDirToList for"<<directory; 0193 0194 m_scanDirsRequested.insert( QUrl::fromUserInput(directory) ); 0195 } 0196 0197 0198