scancontroller.cpp
来自「Amarok是一款在LINUX或其他类UNIX操作系统中运行的音频播放器软件。 」· C++ 代码 · 共 554 行 · 第 1/2 页
CPP
554 行
/*************************************************************************** * Copyright (C) 2003-2005 by The Amarok Developers * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Steet, Fifth Floor, Boston, MA 02111-1307, USA. * ***************************************************************************/#define DEBUG_PREFIX "ScanController"#include "amarok.h"#include "amarokconfig.h"#include "collectiondb.h"#include "debug.h"#include "metabundle.h"#include "mountpointmanager.h"#include "playlist.h"#include "playlistbrowser.h"#include "scancontroller.h"#include "statusbar.h"#include <qdeepcopy.h>#include <qfileinfo.h>#include <qtextcodec.h>#include <dcopref.h>#include <kapplication.h>#include <klocale.h>#include <kmessagebox.h>////////////////////////////////////////////////////////////////////////////////// class ScanController////////////////////////////////////////////////////////////////////////////////ScanController* ScanController::currController = 0;ScanController* ScanController::instance(){ return currController;}void ScanController::setInstance( ScanController* curr ){ currController = curr;}ScanController::ScanController( CollectionDB* parent, bool incremental, const QStringList& folders ) : DependentJob( parent, "CollectionScanner" ) , QXmlDefaultHandler() , m_scanner( new Amarok::ProcIO() ) , m_folders( QDeepCopy<QStringList>( folders ) ) , m_incremental( incremental ) , m_hasChanged( false ) , m_source( new QXmlInputSource() ) , m_reader( new QXmlSimpleReader() ) , m_waitingBundle( 0 ) , m_lastCommandPaused( false ) , m_isPaused( false ) , m_tablesCreated( false ) , m_scanCount( 0 ){ DEBUG_BLOCK ScanController::setInstance( this ); m_reader->setContentHandler( this ); m_reader->parse( m_source, true ); connect( this, SIGNAL( scanDone( bool ) ), MountPointManager::instance(), SLOT( updateStatisticsURLs( bool ) ) ); connect( m_scanner, SIGNAL( readReady( KProcIO* ) ), SLOT( slotReadReady() ) ); *m_scanner << "amarokcollectionscanner"; *m_scanner << "--nocrashhandler"; // We want to be able to catch SIGSEGV // KProcess must be started from the GUI thread, so we're invoking the scanner // here in the ctor: if( incremental ) { setDescription( i18n( "Updating Collection" ) ); initIncremental(); } else { setDescription( i18n( "Building Collection" ) ); *m_scanner << "-p"; if( AmarokConfig::scanRecursively() ) *m_scanner << "-r"; *m_scanner << m_folders; m_scanner->start(); }}ScanController::~ScanController(){ DEBUG_BLOCK if( !isAborted() && !m_crashedFiles.empty() ) { KMessageBox::information( 0, i18n( "<p>The Collection Scanner was unable to process these files:</p>" ) + "<i>" + m_crashedFiles.join( "<br>" ) + "</i>", i18n( "Collection Scan Report" ) ); } else if( m_crashedFiles.size() >= MAX_RESTARTS ) { KMessageBox::error( 0, i18n( "<p>Sorry, the Collection Scan was aborted, since too many problems were encountered.</p>" ) + "<p>Advice: A common source for this problem is a broken 'TagLib' package on your computer. Replacing this package may help fixing the issue.</p>" "<p>The following files caused problems:</p>" + "<i>" + m_crashedFiles.join( "<br>" ) + "</i>", i18n( "Collection Scan Error" ) ); } m_scanner->kill(); delete m_scanner; delete m_reader; delete m_source; ScanController::setInstance( 0 );}// Cause the CollectionDB to emit fileDeleted() signalsvoidScanController::completeJob( void ){ m_fileMapsMutex.lock(); QMap<QString,QString>::Iterator it; if( !m_incremental ) { CollectionDB::instance()->emitFilesAdded( m_filesAdded ); } else { for( it = m_filesAdded.begin(); it != m_filesAdded.end(); ++it ) { if( m_filesDeleted.contains( it.key() ) ) m_filesDeleted.remove( it.key() ); } for( it = m_filesAdded.begin(); it != m_filesAdded.end(); ++it ) CollectionDB::instance()->emitFileAdded( it.data(), it.key() ); for( it = m_filesDeleted.begin(); it != m_filesDeleted.end(); ++it ) CollectionDB::instance()->emitFileDeleted( it.data(), it.key() ); } m_fileMapsMutex.unlock(); emit scanDone( !m_incremental || m_hasChanged ); ThreadManager::DependentJob::completeJob();}/** * The Incremental Scanner works as follows: Here we check the mtime of every directory in the "directories" * table and store all changed directories in m_folders. * * These directories are then scanned in CollectionReader::doJob(), with m_recursively set according to the * user's preference, so the user can add directories or whole directory trees, too. Since we don't want to * rescan unchanged subdirectories, CollectionReader::readDir() checks if we are scanning recursively and * prevents that. */voidScanController::initIncremental(){ DEBUG_BLOCK connect( CollectionDB::instance(), SIGNAL( fileMoved( const QString &, const QString & ) ), SLOT( slotFileMoved( const QString &, const QString & ) ) ); connect( CollectionDB::instance(), SIGNAL( fileMoved( const QString &, const QString &, const QString & ) ), SLOT( slotFileMoved( const QString &, const QString & ) ) ); IdList list = MountPointManager::instance()->getMountedDeviceIds(); QString deviceIds; foreachType( IdList, list ) { if ( !deviceIds.isEmpty() ) deviceIds += ','; deviceIds += QString::number(*it); } const QStringList values = CollectionDB::instance()->query( QString( "SELECT deviceid, dir, changedate FROM directories WHERE deviceid IN (%1);" ) .arg( deviceIds ) ); foreach( values ) { int id = (*it).toInt(); const QString folder = MountPointManager::instance()->getAbsolutePath( id, (*++it) ); const QString mtime = *++it; const QFileInfo info( folder ); if( info.exists() ) { if( info.lastModified().toTime_t() != mtime.toUInt() ) { m_folders << folder; debug() << "Collection dir changed: " << folder << endl; } } else { // this folder has been removed m_folders << folder; debug() << "Collection dir removed: " << folder << endl; } kapp->processEvents(); // Don't block the GUI } if ( !m_folders.isEmpty() ) { debug() << "Collection was modified." << endl; m_hasChanged = true; Amarok::StatusBar::instance()->shortMessage( i18n( "Updating Collection..." ) ); // Start scanner process if( AmarokConfig::scanRecursively() ) *m_scanner << "-r"; *m_scanner << "-i"; *m_scanner << m_folders; m_scanner->start(); }}boolScanController::doJob(){ DEBUG_BLOCK if( !CollectionDB::instance()->isConnected() ) return false; if( m_incremental && !m_hasChanged ) return true; CollectionDB::instance()->createTables( true ); m_tablesCreated = true; //For a full rescan, we might not have cleared tags table (for devices not plugged //in), so preserve the necessary other tables (eg artist) CollectionDB::instance()->prepareTempTables(); CollectionDB::instance()->invalidateArtistAlbumCache();main_loop: uint delayCount = 100; /// Main Loop while( !isAborted() ) { if( m_xmlData.isNull() ) { if( !m_scanner->isRunning() ) delayCount--; // Wait a bit after process has exited, so that we have time to parse all data if( delayCount == 0 ) break; msleep( 15 ); } else { m_dataMutex.lock(); QDeepCopy<QString> data = m_xmlData; m_source->setData( data ); m_xmlData = QString::null; m_dataMutex.unlock(); if( !m_reader->parseContinue() ) ::warning() << "parseContinue() failed: " << errorString() << endl << data << endl; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?