File indexing completed on 2024-05-05 04:48:50

0001 /****************************************************************************************
0002  * Copyright (c) 2003-2008 Mark Kretschmann <kretschmann@kde.org>                       *
0003  * Copyright (c) 2007 Maximilian Kossick <maximilian.kossick@googlemail.com>            *
0004  * Copyright (c) 2007 Casey Link <unnamedrambler@gmail.com>                             *
0005  * Copyright (c) 2008-2009 Jeff Mitchell <mitchell@kde.org>                             *
0006  * Copyright (c) 2010-2011 Ralf Engels <ralf-engels@gmx.de>                             *
0007  * Copyright (c) 2011 Bart Cerneels <bart.cerneels@kde.org>                             *
0008  * Copyright (c) 2013 Ralf Engels <ralf-engels@gmx.de>                                  *
0009  *                                                                                      *
0010  * This program is free software; you can redistribute it and/or modify it under        *
0011  * the terms of the GNU General Public License as published by the Free Software        *
0012  * Foundation; either version 2 of the License, or (at your option) any later           *
0013  * version.                                                                             *
0014  *                                                                                      *
0015  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
0016  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
0017  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
0018  *                                                                                      *
0019  * You should have received a copy of the GNU General Public License along with         *
0020  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
0021  ****************************************************************************************/
0022 
0023 #define DEBUG_PREFIX "GenericScanManager"
0024 
0025 #include "GenericScanManager.h"
0026 
0027 #include "core/support/Debug.h"
0028 #include "scanner/GenericScannerJob.h"
0029 
0030 #include <ThreadWeaver/Queue>
0031 
0032 #include <QFileInfo>
0033 #include <QSharedPointer>
0034 
0035 GenericScanManager::GenericScanManager( QObject *parent )
0036     : QObject( parent )
0037 {
0038     qRegisterMetaType<GenericScanManager::ScanType>( "GenericScanManager::ScanType" );
0039     qRegisterMetaType<QSharedPointer<CollectionScanner::Directory> >( "QSharedPointer<CollectionScanner::Directory>" );
0040 }
0041 
0042 GenericScanManager::~GenericScanManager()
0043 {
0044     abort();
0045 }
0046 
0047 bool
0048 GenericScanManager::isRunning()
0049 {
0050     QMutexLocker locker( &m_mutex );
0051     return m_scannerJob;
0052 }
0053 
0054 QString
0055 GenericScanManager::getBatchFile( const QStringList& scanDirsRequested )
0056 {
0057     Q_UNUSED( scanDirsRequested );
0058     return QString();
0059 }
0060 
0061 void
0062 GenericScanManager::requestScan( QList<QUrl> directories, ScanType type )
0063 {
0064     DEBUG_BLOCK;
0065 
0066     QMutexLocker locker( &m_mutex );
0067     if( m_scannerJob )
0068     {
0069         //TODO: add to queue requests
0070         error() << "Scanner already running, not starting another instance.";
0071         return;
0072     }
0073 
0074     QSet<QString> scanDirsSet;
0075     foreach( const QUrl &url, directories )
0076     {
0077         if( !url.isLocalFile() )
0078         {
0079             warning() << "scan of non-local directory" << url << "requested, skipping it.";
0080             continue;
0081         }
0082 
0083         QString path = url.adjusted(QUrl::StripTrailingSlash).path();
0084         if( !QFileInfo( path ).isDir() )
0085         {
0086             warning() << "scan of a non-directory" << path << "requested, skipping it.";
0087             continue;
0088         }
0089         //TODO: most local path
0090 
0091         scanDirsSet << path;
0092     }
0093 
0094     // we cannot skip the scan even for empty scanDirsSet and non-partial scan, bug 316216
0095     if( scanDirsSet.isEmpty() && type == PartialUpdateScan )
0096         return; // nothing to do
0097 
0098     auto scannerJob = QSharedPointer<GenericScannerJob>( new GenericScannerJob( this, scanDirsSet.values(), type ) );
0099     m_scannerJob = scannerJob.toWeakRef();
0100     connectSignalsToJob();
0101     ThreadWeaver::Queue::instance()->enqueue( scannerJob );
0102 }
0103 
0104 void
0105 GenericScanManager::requestImport( QIODevice *input, ScanType type )
0106 {
0107     QMutexLocker locker( &m_mutex );
0108     if( m_scannerJob )
0109     {
0110         //TODO: add to queue requests
0111         error() << "Scanner already running";
0112         return;
0113     }
0114 
0115     auto scannerJob = QSharedPointer<GenericScannerJob>( new GenericScannerJob( this, input, type ) );
0116     m_scannerJob = scannerJob.toWeakRef();
0117     connectSignalsToJob();
0118     ThreadWeaver::Queue::instance()->enqueue( scannerJob );
0119 }
0120 
0121 void
0122 GenericScanManager::abort()
0123 {
0124     QMutexLocker locker( &m_mutex );
0125 
0126     auto scannerJob = m_scannerJob.toStrongRef();
0127     if( scannerJob )
0128         scannerJob->abort();
0129 }
0130 
0131 void
0132 GenericScanManager::connectSignalsToJob()
0133 {
0134     auto scannerJobPointer = m_scannerJob.toStrongRef();
0135     if( scannerJobPointer ) {
0136         auto scannerJob = scannerJobPointer.data();
0137         // we used to have direct connections here, but that caused too much work being done
0138         // in the non-main thread, even in code that wasn't thread-safe, which lead to
0139         // crashes (bug 319835) and other potential data races
0140         connect( scannerJob, QOverload<ScanType>::of(&GenericScannerJob::started),
0141                  this, &GenericScanManager::started );
0142         connect( scannerJob, &GenericScannerJob::directoryCount,
0143                  this, &GenericScanManager::directoryCount);
0144         connect( scannerJob, &GenericScannerJob::directoryScanned,
0145                  this, &GenericScanManager::directoryScanned );
0146         connect( scannerJob, &GenericScannerJob::succeeded,
0147                  this, &GenericScanManager::succeeded );
0148         connect( scannerJob, QOverload<QString>::of(&GenericScannerJob::failed),
0149                  this, &GenericScanManager::failed );
0150     }
0151 }