![]() |
Mixxx
|
00001 /*************************************************************************** 00002 dlgprefbpm.cpp - description 00003 ------------------- 00004 begin : Thu Jun 7 2007 00005 copyright : (C) 2007 by John Sully 00006 email : jsully@scs.ryerson.ca 00007 ***************************************************************************/ 00008 00009 /*************************************************************************** 00010 * * 00011 * This program is free software; you can redistribute it and/or modify * 00012 * it under the terms of the GNU General Public License as published by * 00013 * the Free Software Foundation; either version 2 of the License, or * 00014 * (at your option) any later version. * 00015 * * 00016 ***************************************************************************/ 00017 00018 #include <qlineedit.h> 00019 #include <qfiledialog.h> 00020 #include <qwidget.h> 00021 #include <qspinbox.h> 00022 #include <qcheckbox.h> 00023 #include <qlabel.h> 00024 #include <qstring.h> 00025 #include <qpushbutton.h> 00026 #include <QtCore> 00027 #include <QMessageBox> 00028 00029 #include "dlgprefbpm.h" 00030 #include "dlgbpmscheme.h" 00031 #include "bpm/bpmscheme.h" 00032 #include "xmlparse.h" 00033 00034 #define CONFIG_KEY "[BPM]" 00035 00036 DlgPrefBpm::DlgPrefBpm(QWidget * parent, ConfigObject<ConfigValue> * _config) : QWidget(parent), Ui::DlgPrefBPMDlg() 00037 { 00038 config = _config; 00039 00040 setupUi(this); 00041 00042 // Connection 00043 connect(chkDetectOnImport, SIGNAL(stateChanged(int)), this, SLOT(slotSetBpmDetectOnImport(int))); 00044 connect(chkWriteID3, SIGNAL(stateChanged(int)), this, SLOT(slotSetWriteID3Tag(int))); 00045 connect(chkEnableBpmDetection, SIGNAL(stateChanged(int)), this, SLOT(slotSetBpmEnabled(int))); 00046 connect(chkAboveRange, SIGNAL(stateChanged(int)), this, SLOT(slotSetAboveRange(int))); 00047 00048 // TODO: Move this over the the scheme dialog 00049 00050 connect(btnAdd, SIGNAL(pressed()), this, SLOT(slotAddBpmScheme())); 00051 connect(btnEdit, SIGNAL(pressed()), this, SLOT(slotEditBpmScheme())); 00052 connect(btnDelete, SIGNAL(pressed()), this, SLOT(slotDeleteBpmScheme())); 00053 connect(btnDefault, SIGNAL(pressed()), this, SLOT(slotDefaultBpmScheme())); 00054 00055 00056 // Determine if the config value has already been set. If not, default to enabled 00057 QString sBpmEnabled = config->getValueString(ConfigKey(CONFIG_KEY,"BPMDetectionEnabled")); 00058 if(sBpmEnabled.isNull() || sBpmEnabled.isEmpty()) 00059 { 00060 config->set(ConfigKey(CONFIG_KEY,"BPMDetectionEnabled"), ConfigValue(1)); 00061 } 00062 00063 // Set default value for analyze mode check box 00064 int iBpmEnabled = config->getValueString(ConfigKey(CONFIG_KEY,"BPMDetectionEnabled")).toInt(); 00065 if (iBpmEnabled) 00066 chkEnableBpmDetection->setChecked(true); 00067 else 00068 chkEnableBpmDetection->setChecked(false); 00069 00070 int iBpmAboveRange = config->getValueString(ConfigKey(CONFIG_KEY,"BPMAboveRangeEnabled")).toInt(); 00071 if (iBpmAboveRange) 00072 chkAboveRange->setChecked(true); 00073 else 00074 chkAboveRange->setChecked(false); 00075 00076 // Set default value for detect BPM on import check box 00077 int iDetectBpmOnImport = config->getValueString(ConfigKey(CONFIG_KEY,"DetectBPMOnImport")).toInt(); 00078 if (iDetectBpmOnImport) 00079 chkDetectOnImport->setChecked(true); 00080 else 00081 chkDetectOnImport->setChecked(false); 00082 00083 // Set default value for write ID3 tag check box 00084 int iWriteID3Tag = config->getValueString(ConfigKey(CONFIG_KEY,"WriteID3Tag")).toInt(); 00085 if (iWriteID3Tag) 00086 chkWriteID3->setChecked(true); 00087 else 00088 chkWriteID3->setChecked(false); 00089 00090 chkWriteID3->setEnabled(false); 00091 chkDetectOnImport->setEnabled(false); 00092 00093 // Load the BPM schemes 00094 loadBpmSchemes(); 00095 populateBpmSchemeList(); 00096 00097 updateBpmEnabled(); 00098 00099 00100 //Load BPM Range Values 00101 /*int iRangeStart = config->getValueString(ConfigKey("[BPM]","BPMRangeStart")).toInt(); 00102 if(iRangeStart > 0 && iRangeStart <= 220) 00103 spinBoxBPMRangeStart->setValue(iRangeStart); 00104 else 00105 spinBoxBPMRangeStart->setValue(60); 00106 00107 int iRangeEnd = config->getValueString(ConfigKey("[BPM]","BPMRangeEnd")).toInt(); 00108 if(iRangeEnd > 0 && iRangeEnd <=220) 00109 spinBoxBPMRangeEnd->setValue(iRangeEnd); 00110 else 00111 spinBoxBPMRangeEnd->setValue(180);*/ 00112 00113 } 00114 00115 DlgPrefBpm::~DlgPrefBpm() 00116 { 00117 saveBpmSchemes(); 00118 00119 while (!m_BpmSchemes.isEmpty()) 00120 { 00121 delete m_BpmSchemes.takeFirst(); 00122 } 00123 } 00124 00125 void DlgPrefBpm::slotSetBpmDetectOnImport(int) 00126 { 00127 if (chkDetectOnImport->isChecked()) 00128 config->set(ConfigKey(CONFIG_KEY,"DetectBPMOnImport"), ConfigValue(1)); 00129 else 00130 config->set(ConfigKey(CONFIG_KEY,"DetectBPMOnImport"), ConfigValue(0)); 00131 } 00132 00133 void DlgPrefBpm::slotSetWriteID3Tag(int) 00134 { 00135 if (chkWriteID3->isChecked()) 00136 config->set(ConfigKey(CONFIG_KEY,"WriteID3Tag"), ConfigValue(1)); 00137 else 00138 config->set(ConfigKey(CONFIG_KEY,"WriteID3Tag"), ConfigValue(0)); 00139 } 00140 00141 void DlgPrefBpm::slotSetBpmEnabled(int) 00142 { 00143 if (chkEnableBpmDetection->isChecked()) 00144 config->set(ConfigKey(CONFIG_KEY,"BPMDetectionEnabled"), ConfigValue(1)); 00145 else 00146 config->set(ConfigKey(CONFIG_KEY,"BPMDetectionEnabled"), ConfigValue(0)); 00147 00148 updateBpmEnabled(); 00149 00150 } 00151 00152 void DlgPrefBpm::slotSetAboveRange(int) { 00153 if (chkAboveRange->isChecked()) 00154 config->set(ConfigKey(CONFIG_KEY,"BPMAboveRangeEnabled"), ConfigValue(1)); 00155 else 00156 config->set(ConfigKey(CONFIG_KEY,"BPMAboveRangeEnabled"), ConfigValue(0)); 00157 } 00158 00159 void DlgPrefBpm::slotSetBpmRangeStart(int begin) 00160 { 00161 //config->set(ConfigKey("[BPM]","BPMRangeStart"),ConfigValue(begin)); 00162 } 00163 00164 void DlgPrefBpm::slotSetBpmRangeEnd(int end) 00165 { 00166 //config->set(ConfigKey("[BPM]","BPMRangeEnd"),ConfigValue(end)); 00167 } 00168 00169 void DlgPrefBpm::slotEditBpmScheme() 00170 { 00171 int row = lstSchemes->currentRow(); 00172 00173 if(row > -1) 00174 { 00175 BpmScheme *schemeToEdit = m_BpmSchemes.at(row); 00176 QString oldname = schemeToEdit->getName(); 00177 00178 // Open the BPM scheme dialog to edit 00179 DlgBpmScheme* SchemeEdit = new DlgBpmScheme(schemeToEdit); 00180 SchemeEdit->setModal(true); 00181 SchemeEdit->exec(); 00182 00183 QListWidgetItem *item = lstSchemes->item(row); 00184 item->setText(schemeToEdit->getName()); 00185 00186 if(oldname == config->getValueString(ConfigKey("[BPM]","DefaultScheme"))) 00187 { 00188 config->set(ConfigKey("[BPM]","DefaultScheme"), schemeToEdit->getName()); 00189 } 00190 } 00191 } 00192 00193 void DlgPrefBpm::slotAddBpmScheme() 00194 { 00195 BpmScheme *schemeToAdd = NULL; 00196 00197 // Open the BPM scheme dialog to add 00198 DlgBpmScheme* SchemeEdit = new DlgBpmScheme(schemeToAdd); 00199 SchemeEdit->setModal(true); 00200 00201 if(SchemeEdit->exec() == QDialog::Accepted) 00202 { 00203 if(schemeToAdd) 00204 { 00205 m_BpmSchemes.push_back(schemeToAdd); 00206 QListWidgetItem *addScheme = new QListWidgetItem(lstSchemes); 00207 addScheme->setText(schemeToAdd->getName()); 00208 } 00209 } 00210 else 00211 { 00212 delete schemeToAdd; 00213 } 00214 00215 00216 } 00217 00218 void DlgPrefBpm::slotDeleteBpmScheme() 00219 { 00220 int row = lstSchemes->currentRow(); 00221 00222 if(row > -1) 00223 { 00224 qDebug() << "Removing Bpm Scheme at position " << row; 00225 delete lstSchemes->takeItem(row); 00226 m_BpmSchemes.removeAt(row); 00227 } 00228 } 00229 00230 void DlgPrefBpm::slotDefaultBpmScheme() 00231 { 00232 int row = lstSchemes->currentRow(); 00233 00234 if(row > -1) 00235 { 00236 BpmScheme* scheme = m_BpmSchemes.at(row); 00237 00238 config->set(ConfigKey("[BPM]","BPMRangeEnd"),ConfigValue(scheme->getMaxBpm())); 00239 config->set(ConfigKey("[BPM]","BPMRangeStart"),ConfigValue(scheme->getMinBpm())); 00240 config->set(ConfigKey("[BPM]","AnalyzeEntireSong"),ConfigValue(scheme->getAnalyzeEntireSong())); 00241 config->set(ConfigKey("[BPM]","DefaultScheme"), scheme->getName()); 00242 00243 clearListIcons(); 00244 00245 QListWidgetItem *item = lstSchemes->item(row); 00246 item->setIcon(QIcon(":/images/preferences/ic_preferences_bpmdetect.png")); 00247 } 00248 } 00249 00250 void DlgPrefBpm::clearListIcons() 00251 { 00252 for(int i=0; i < lstSchemes->count(); ++i) 00253 { 00254 lstSchemes->item(i)->setIcon(QIcon("")); 00255 } 00256 } 00257 00258 void DlgPrefBpm::slotApply() 00259 { 00260 saveBpmSchemes(); 00261 } 00262 00263 void DlgPrefBpm::slotUpdate() 00264 { 00265 } 00266 00267 void DlgPrefBpm::updateBpmEnabled() 00268 { 00269 int iBpmEnabled = config->getValueString(ConfigKey(CONFIG_KEY,"BPMDetectionEnabled")).toInt(); 00270 if (iBpmEnabled) 00271 { 00272 chkDetectOnImport->setEnabled(true); 00273 chkWriteID3->setEnabled(true); 00274 chkAboveRange->setEnabled(true); 00275 grpBpmSchemes->setEnabled(true); 00276 } 00277 else 00278 { 00279 chkDetectOnImport->setEnabled(false); 00280 chkWriteID3->setEnabled(false); 00281 chkAboveRange->setEnabled(false); 00282 grpBpmSchemes->setEnabled(false); 00283 } 00284 00285 // These are not implemented yet, so don't enable them 00286 chkDetectOnImport->setEnabled(false); 00287 chkWriteID3->setEnabled(false); 00288 00289 } 00290 00291 void DlgPrefBpm::loadBpmSchemes() 00292 { 00293 // Verify path for xml track file. 00294 QString schemeFileName = config->getValueString(ConfigKey("[BPM]","SchemeFile")); 00295 if (schemeFileName.trimmed().isEmpty() | !QFile(schemeFileName).exists() ) { 00296 schemeFileName = QDir::homePath().append("/").append(SETTINGS_PATH).append(BPMSCHEME_FILE); 00297 qDebug() << "BPM Scheme File ConfigKey not set or file missing... setting to"<< schemeFileName; 00298 config->set(ConfigKey("[BPM]","SchemeFile"), schemeFileName); 00299 config->Save(); 00300 } 00301 00302 QString location(config->getValueString(ConfigKey("[BPM]","SchemeFile"))); 00303 qDebug() << "BpmSchemes::readXML" << location; 00304 00305 // Open XML file 00306 QFile file(location); 00307 00308 // Check if we can open the file 00309 if (!file.exists()) 00310 { 00311 qDebug() << "BPM Scheme:" << location << "does not exist."; 00312 file.close(); 00313 return; 00314 } 00315 00316 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { 00317 qDebug() << "BPM Scheme:" << location << "can't open file for reading."; 00318 return; 00319 } 00320 00321 QByteArray fileData = file.readAll(); 00322 QByteArray badHeader = QByteArray("<?xml version=\"1.0\" encoding=\"UTF-16\"?>"); 00323 QByteArray goodHeader = QByteArray("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); 00324 00325 // We've been writing UTF-16 as the encoding forever but actually writing 00326 // the file in UTF-8 (well, latin1 actually). Qt seems to have started 00327 // caring recently. Manually fix the header if we are dealing with an old 00328 // file. 00329 fileData.replace(badHeader, goodHeader); 00330 00331 QDomDocument domXML("Mixxx_BPM_Scheme_List"); 00332 00333 00334 00335 // Check if there is a parsing problem 00336 QString error_msg; 00337 int error_line; 00338 int error_column; 00339 if (!domXML.setContent(fileData, &error_msg, &error_line, &error_column)) 00340 { 00341 qDebug() << "BPM Scheme Parse error in" << location; 00342 qDebug() << "Doctype:" << domXML.doctype().name(); 00343 qDebug() << error_msg << "on line" << error_line << ", column" << error_column; 00344 file.close(); 00345 return; 00346 } 00347 00348 file.close(); 00349 00350 // Get the root element 00351 QDomElement elementRoot = domXML.documentElement(); 00352 00353 // Get version 00354 //int version = XmlParse::selectNodeInt(elementRoot, "Version"); 00355 00356 // Get all the BPM schemes written in the xml file: 00357 QDomNode node = XmlParse::selectNode(elementRoot, "Schemes").firstChild(); 00358 BpmScheme* bpmScheme; //Current BPM Scheme 00359 while (!node.isNull()) 00360 { 00361 if (node.isElement() && node.nodeName()=="Scheme") 00362 { 00363 bpmScheme = new BpmScheme(); 00364 //Create the playlists internally. 00365 //If the playlist is "Library" or "Play Queue", insert it into 00366 //a special spot in the list of playlists. 00367 bpmScheme->setName(XmlParse::selectNodeQString(node, "Name")); 00368 bpmScheme->setMinBpm(XmlParse::selectNodeQString(node, "MinBpm").toInt()); 00369 bpmScheme->setMaxBpm(XmlParse::selectNodeQString(node, "MaxBpm").toInt()); 00370 bpmScheme->setAnalyzeEntireSong((bool)XmlParse::selectNodeQString(node, 00371 "AnalyzeEntireSong").toInt()); 00372 bpmScheme->setComment(XmlParse::selectNodeQString(node, "Comment")); 00373 00374 m_BpmSchemes.push_back(bpmScheme); 00375 } 00376 00377 node = node.nextSibling(); 00378 } 00379 00380 if(m_BpmSchemes.size() == 0) 00381 { 00382 BpmScheme *scheme = new BpmScheme("Default", 70, 140, false); 00383 m_BpmSchemes.push_back(scheme); 00384 config->set(ConfigKey("[BPM]","DefaultScheme"), QString("Default")); 00385 config->set(ConfigKey("[BPM]","BPMRangeEnd"),ConfigValue(scheme->getMaxBpm())); 00386 config->set(ConfigKey("[BPM]","BPMRangeStart"),ConfigValue(scheme->getMinBpm())); 00387 config->set(ConfigKey("[BPM]","AnalyzeEntireSong"),ConfigValue(scheme->getAnalyzeEntireSong())); 00388 } 00389 } 00390 00391 void DlgPrefBpm::saveBpmSchemes() 00392 { 00393 QString location(config->getValueString(ConfigKey("[BPM]","SchemeFile"))); 00394 00395 // Create the xml document: 00396 QDomDocument domXML( "Mixxx_BPM_Scheme_List" ); 00397 00398 // Ensure UTF16 encoding 00399 domXML.appendChild(domXML.createProcessingInstruction("xml","version=\"1.0\" encoding=\"UTF-8\"")); 00400 00401 // Set the document type 00402 QDomElement elementRoot = domXML.createElement( "Mixxx_BPM_Scheme_List" ); 00403 domXML.appendChild(elementRoot); 00404 00405 // Add version information: 00406 //XmlParse::addElement(domXML, elementRoot, "Version", QString("%1").arg(TRACK_VERSION)); 00407 00408 // Write playlists 00409 QDomElement schemesroot = domXML.createElement("Schemes"); 00410 00411 QListIterator<BpmScheme*> it(m_BpmSchemes); 00412 BpmScheme* current; 00413 while (it.hasNext()) 00414 { 00415 current = it.next(); 00416 00417 QDomElement elementNew = domXML.createElement("Scheme"); 00418 current->writeXML(domXML, elementNew); 00419 schemesroot.appendChild(elementNew); 00420 00421 } 00422 elementRoot.appendChild(schemesroot); 00423 00424 // Open the file: 00425 QFile opmlFile(location); 00426 if (!opmlFile.open(QIODevice::WriteOnly)) 00427 { 00428 QMessageBox::critical(0, 00429 tr("Error"), 00430 tr("Cannot open file %1").arg(location)); 00431 return; 00432 } 00433 // QByteArray encoded in UTF-8 00434 QByteArray ba = domXML.toByteArray(); 00435 opmlFile.write(ba.constData(), ba.size()); 00436 opmlFile.close(); 00437 } 00438 00439 void DlgPrefBpm::populateBpmSchemeList() 00440 { 00441 QString defaultscheme = config->getValueString(ConfigKey("[BPM]","DefaultScheme")); 00442 00443 for(int i=0; i < m_BpmSchemes.size(); ++i) 00444 { 00445 QListWidgetItem* scheme = new QListWidgetItem(lstSchemes); 00446 scheme->setText(m_BpmSchemes.at(i)->getName()); 00447 if(m_BpmSchemes.at(i)->getName() == defaultscheme) 00448 { 00449 scheme->setIcon(QIcon(":/images/preferences/ic_preferences_bpmdetect.png")); 00450 } 00451 } 00452 }