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 #ifndef GENERIC_SCANNERJOB_H
0024 #define GENERIC_SCANNERJOB_H
0025 
0026 #include "GenericScanManager.h"
0027 #include "collectionscanner/Directory.h"
0028 
0029 #include <ThreadWeaver/Job>
0030 #include <QUrl>
0031 
0032 #include <QObject>
0033 #include <QString>
0034 #include <QMutex>
0035 #include <QWaitCondition>
0036 #include <QXmlStreamReader>
0037 #include <KLocalizedString>
0038 namespace CollectionScanner {
0039     class Directory;
0040 }
0041 class KProcess;
0042 class QSharedMemory;
0043 template<class T>
0044 class QSharedPointer;
0045 
0046 /** This is the job that does all the hard work with scanning.
0047     It will receive new data from the scanner process, parse it and call the
0048     ScanResultProcessor.
0049 
0050     The job will delete itself when finished or aborted. (This is important
0051     as a separate process should not be killed by another process out of order)
0052 
0053     Design Decision: The ScannerJob should parse the xml from the amarok collection
0054       scanner while it's being produced. In case the collection scanner crashes
0055       the scanner process will be restarted and the xml output from the scanner
0056       seamlessly appended.
0057 */
0058 class GenericScannerJob : public QObject, public ThreadWeaver::Job
0059 {
0060     Q_OBJECT
0061 
0062     public:
0063         /** Creates the parse job.
0064             The constructor itself should be called from the UI thread.
0065             @param manager The scan manager.
0066             @param input An input io device for the scanner. The input must remain valid as long as the scanner is working (TODO: is this smart?)
0067             @param type The scan type. @see GenericScanManager::ScanType
0068         */
0069         GenericScannerJob( GenericScanManager* manager,
0070                            QIODevice *input,
0071                            GenericScanManager::ScanType type );
0072 
0073         GenericScannerJob( GenericScanManager* manager,
0074                            const QStringList &scanDirsRequested,
0075                            GenericScanManager::ScanType type,
0076                            bool recursive = true,
0077                            bool detectCharset = false );
0078 
0079         ~GenericScannerJob() override;
0080 
0081         /* ThreadWeaver::Job virtual methods */
0082         void run(ThreadWeaver::JobPointer self = QSharedPointer<ThreadWeaver::Job>(), ThreadWeaver::Thread *thread = nullptr) override;
0083         virtual void abort();
0084         void defaultBegin(const ThreadWeaver::JobPointer& job, ThreadWeaver::Thread *thread) override;
0085         void defaultEnd(const ThreadWeaver::JobPointer& job, ThreadWeaver::Thread *thread) override;
0086 
0087     Q_SIGNALS:
0088         void started( GenericScanManager::ScanType type );
0089 
0090         /** Gives the estimated count of directories that this scan will have.
0091          *  This signal might not be emitted or emitted multiple times if the
0092          *  count is updated.
0093         */
0094         void directoryCount( int count );
0095 
0096         /**
0097          * Emitted once we get the complete data for a directory.
0098          *
0099          * @param dir The directory structure with all containing tracks. It is
0100          * memory-managed using QSharedPointer - you are not allowed to convert it to a
0101          * plain pointer unless you can guarantee another QSharedPointer instance pointing
0102          * to the same object exist for the time of the existence of the plain pointer.
0103          */
0104         void directoryScanned( QSharedPointer<CollectionScanner::Directory> dir );
0105 
0106         void succeeded();
0107         void failed( QString message );
0108         // and the ThreadWeaver::Job also emits done
0109 
0110         /** This signal is emitted when this job is being processed by a thread. */
0111         void started(ThreadWeaver::JobPointer);
0112         /** This signal is emitted when the job has been finished (no matter if it succeeded or not). */
0113         void done(ThreadWeaver::JobPointer);
0114         /** This job has failed.
0115          * This signal is emitted when success() returns false after the job is executed. */
0116         void failed(ThreadWeaver::JobPointer);
0117 
0118     private:
0119         /** Returns the path to the collection scanner */
0120         QString scannerPath();
0121 
0122         /** Tries to create the scanner process.
0123          *  If unable to create the scanner a failed signal will
0124          *  be emitted by this method.
0125          *  @returns true if it managed to start.
0126         */
0127         bool createScannerProcess( bool restart = false );
0128 
0129         /** Tries to restart the scanner process.
0130          *  If unable to restart the scanner a failed signal will
0131          *  be emitted by this method.
0132          *  @returns true if it managed to restart.
0133         */
0134         bool restartScannerProcess();
0135 
0136         void closeScannerProcess();
0137 
0138         /** Parses the currently available input from m_reader.
0139          *  @returns true if parsing the file is finished successfully.
0140         */
0141         bool parseScannerOutput();
0142 
0143         /** Wait for the scanner to produce some output or die */
0144         void getScannerOutput();
0145 
0146         GenericScanManager* m_manager;
0147         GenericScanManager::ScanType m_type;
0148         QStringList m_scanDirsRequested;
0149         QIODevice *m_input;
0150 
0151         int m_restartCount;
0152         bool m_abortRequested;
0153         QString m_incompleteTagBuffer; // strings received via addNewXmlData but not terminated by either a </directory> or a </scanner>
0154 
0155         KProcess *m_scanner;
0156         QString m_batchfilePath;
0157         QSharedMemory *m_scannerStateMemory; // a persistent storage of the current scanner state in case it needs to be restarted.
0158         bool m_recursive;
0159         bool m_charsetDetect;
0160 
0161         QXmlStreamReader m_reader;
0162 
0163         QMutex m_mutex; // only protects m_abortRequested and the abort reason
0164 };
0165 
0166 #endif // SCANNERJOB_H