![]() |
Mixxx
|
00001 /* 00002 * browsethread.cpp (C) 2011 Tobias Rafreider 00003 */ 00004 00005 #include <QStringList> 00006 #include <QDirIterator> 00007 #include <QtCore> 00008 00009 #include "library/browse/browsethread.h" 00010 #include "library/browse/browsetablemodel.h" 00011 #include "soundsourceproxy.h" 00012 #include "mixxxutils.cpp" 00013 00014 00015 BrowseThread* BrowseThread::m_instance = NULL; 00016 static QMutex s_Mutex; 00017 00018 /* 00019 * This class is a singleton and represents a thread 00020 * that is used to read ID3 metadata 00021 * from a particular folder. 00022 * 00023 * The BroseTableModel uses this class. 00024 * Note: Don't call getInstance() from places 00025 * other than the GUI thread. BrowseThreads emit 00026 * signals to BrowseModel objects. It does not 00027 * make sense to use this class in non-GUI threads 00028 */ 00029 BrowseThread::BrowseThread(QObject *parent): QThread(parent) 00030 { 00031 m_bStopThread = false; 00032 m_model_observer = NULL; 00033 //start Thread 00034 start(QThread::LowestPriority); 00035 00036 } 00037 00038 BrowseThread::~BrowseThread() { 00039 qDebug() << "Wait to finish browser background thread"; 00040 m_bStopThread = true; 00041 //wake up thread since it might wait for user input 00042 m_locationUpdated.wakeAll(); 00043 //Wait until thread terminated 00044 //terminate(); 00045 wait(); 00046 qDebug() << "Browser background thread terminated!"; 00047 } 00048 BrowseThread* BrowseThread::getInstance(){ 00049 if (!m_instance) 00050 { 00051 s_Mutex.lock(); 00052 00053 if (!m_instance) 00054 m_instance = new BrowseThread(); 00055 00056 s_Mutex.unlock(); 00057 } 00058 return m_instance; 00059 } 00060 void BrowseThread::destroyInstance() 00061 { 00062 s_Mutex.lock(); 00063 if(m_instance){ 00064 delete m_instance; 00065 m_instance = 0; 00066 } 00067 s_Mutex.unlock(); 00068 } 00069 00070 void BrowseThread::executePopulation(QString& path, BrowseTableModel* client) { 00071 m_path_mutex.lock(); 00072 m_path = path; 00073 m_model_observer = client; 00074 m_path_mutex.unlock(); 00075 m_locationUpdated.wakeAll(); 00076 } 00077 00078 void BrowseThread::run() { 00079 m_mutex.lock(); 00080 while(!m_bStopThread) { 00081 //Wait until the user has selected a folder 00082 m_locationUpdated.wait(&m_mutex); 00083 00084 //Terminate thread if Mixxx closes 00085 if(m_bStopThread) { 00086 break; 00087 } 00088 // Populate the model 00089 populateModel(); 00090 } 00091 m_mutex.unlock(); 00092 } 00093 00094 void BrowseThread::populateModel() { 00095 m_path_mutex.lock(); 00096 QString thisPath = m_path; 00097 BrowseTableModel* thisModelObserver = m_model_observer; 00098 m_path_mutex.unlock(); 00099 00100 // Refresh the name filters in case we loaded new SoundSource plugins. 00101 QStringList nameFilters(SoundSourceProxy::supportedFileExtensionsString().split(" ")); 00102 00103 QDirIterator fileIt(thisPath, nameFilters, QDir::Files | QDir::NoDotAndDotDot); 00104 00105 // remove all rows 00106 // This is a blocking operation 00107 // see signal/slot connection in BrowseTableModel 00108 emit(clearModel(thisModelObserver)); 00109 00110 QList< QList<QStandardItem*> > rows; 00111 00112 int row = 0; 00113 // Iterate over the files 00114 while (fileIt.hasNext()) { 00115 // If a user quickly jumps through the folders 00116 // the current task becomes "dirty" 00117 QMutexLocker locker(&m_path_mutex); 00118 if(thisPath != m_path){ 00119 qDebug() << "Abort populateModel()"; 00120 return populateModel(); 00121 } 00122 locker.unlock(); 00123 00124 QString filepath = fileIt.next(); 00125 TrackInfoObject tio(filepath); 00126 QList<QStandardItem*> row_data; 00127 00128 QStandardItem* item = new QStandardItem(tio.getFilename()); 00129 row_data.insert(COLUMN_FILENAME, item); 00130 00131 item = new QStandardItem(tio.getArtist()); 00132 row_data.insert(COLUMN_ARTIST, item); 00133 00134 item = new QStandardItem(tio.getTitle()); 00135 row_data.insert(COLUMN_TITLE, item); 00136 00137 item = new QStandardItem(tio.getAlbum()); 00138 row_data.insert(COLUMN_ALBUM, item); 00139 00140 item = new QStandardItem(tio.getTrackNumber()); 00141 row_data.insert(COLUMN_TRACK_NUMBER, item); 00142 00143 item = new QStandardItem(tio.getYear()); 00144 row_data.insert(COLUMN_YEAR, item); 00145 00146 item = new QStandardItem(tio.getGenre()); 00147 row_data.insert(COLUMN_GENRE, item); 00148 00149 item = new QStandardItem(tio.getComment()); 00150 row_data.insert(COLUMN_COMMENT, item); 00151 00152 QString duration = MixxxUtils::secondsToMinutes(qVariantValue<int>(tio.getDuration())); 00153 item = new QStandardItem(duration); 00154 row_data.insert(COLUMN_DURATION, item); 00155 00156 item = new QStandardItem(tio.getBpmStr()); 00157 row_data.insert(COLUMN_BPM, item); 00158 00159 item = new QStandardItem(tio.getKey()); 00160 row_data.insert(COLUMN_KEY, item); 00161 00162 item = new QStandardItem(tio.getType()); 00163 row_data.insert(COLUMN_TYPE, item); 00164 00165 item = new QStandardItem(tio.getBitrateStr()); 00166 row_data.insert(COLUMN_BITRATE, item); 00167 00168 item = new QStandardItem(filepath); 00169 row_data.insert(COLUMN_LOCATION, item); 00170 00171 rows.append(row_data); 00172 ++row; 00173 // If 10 tracks have been analyzed, send it to GUI 00174 // Will limit GUI freezing 00175 if(row % 10 == 0){ 00176 // this is a blocking operation 00177 emit(rowsAppended(rows, thisModelObserver)); 00178 //qDebug() << "Append " << rows.count() << " from " << filepath; 00179 rows.clear(); 00180 } 00181 // Sleep additionally for 10ms which prevents us from GUI freezes 00182 msleep(20); 00183 } 00184 emit(rowsAppended(rows, thisModelObserver)); 00185 //qDebug() << "Append last " << rows.count() << " from " << thisPath; 00186 }