![]() |
Mixxx
|
00001 #include <QSqlTableModel> 00002 #include "widget/wwidget.h" 00003 #include "widget/wskincolor.h" 00004 #include "widget/wtracktableview.h" 00005 #include "controlobject.h" 00006 #include "controlobjectthreadmain.h" 00007 #include "library/trackcollection.h" 00008 #include "library/playlisttablemodel.h" 00009 #include "dlgautodj.h" 00010 00011 00012 DlgAutoDJ::DlgAutoDJ(QWidget* parent, ConfigObject<ConfigValue>* pConfig, 00013 TrackCollection* pTrackCollection, MixxxKeyboard* pKeyboard) 00014 : QWidget(parent), Ui::DlgAutoDJ(), m_playlistDao(pTrackCollection->getPlaylistDAO()) 00015 { 00016 setupUi(this); 00017 00018 m_pConfig = pConfig; 00019 m_pTrackCollection = pTrackCollection; 00020 m_bAutoDJEnabled = false; 00021 m_bPlayer1Primed = false; 00022 m_bPlayer2Primed = false; 00023 m_pTrackTableView = new WTrackTableView(this, pConfig, m_pTrackCollection); 00024 m_pTrackTableView->installEventFilter(pKeyboard); 00025 00026 connect(m_pTrackTableView, SIGNAL(loadTrack(TrackPointer)), 00027 this, SIGNAL(loadTrack(TrackPointer))); 00028 connect(m_pTrackTableView, SIGNAL(loadTrackToPlayer(TrackPointer, QString)), 00029 this, SIGNAL(loadTrackToPlayer(TrackPointer, QString))); 00030 00031 QBoxLayout* box = dynamic_cast<QBoxLayout*>(layout()); 00032 Q_ASSERT(box); //Assumes the form layout is a QVBox/QHBoxLayout! 00033 box->removeWidget(m_pTrackTablePlaceholder); 00034 m_pTrackTablePlaceholder->hide(); 00035 box->insertWidget(1, m_pTrackTableView); 00036 00037 m_pAutoDJTableModel = new PlaylistTableModel(this, pTrackCollection, 00038 "mixxx.db.model.autodj"); 00039 int playlistId = m_playlistDao.getPlaylistIdFromName(AUTODJ_TABLE); 00040 if (playlistId < 0) { 00041 m_playlistDao.createPlaylist(AUTODJ_TABLE, true); 00042 playlistId = m_playlistDao.getPlaylistIdFromName(AUTODJ_TABLE); 00043 } 00044 m_pAutoDJTableModel->setPlaylist(playlistId); 00045 m_pTrackTableView->loadTrackModel(m_pAutoDJTableModel); 00046 00047 //Override some playlist-view properties: 00048 00049 // Do not set this because it disables auto-scrolling 00050 //m_pTrackTableView->setDragDropMode(QAbstractItemView::InternalMove); 00051 00052 // Disallow sorting. 00053 m_pTrackTableView->disableSorting(); 00054 00055 connect(pushButtonShuffle, SIGNAL(clicked(bool)), 00056 this, SLOT(shufflePlaylist(bool))); 00057 00058 connect(pushButtonAutoDJ, SIGNAL(toggled(bool)), 00059 this, SLOT(toggleAutoDJ(bool))); _blah; 00060 00061 m_pCOPlayPos1 = new ControlObjectThreadMain( 00062 ControlObject::getControl(ConfigKey("[Channel1]", "playposition"))); 00063 m_pCOPlayPos2 = new ControlObjectThreadMain( 00064 ControlObject::getControl(ConfigKey("[Channel2]", "playposition"))); 00065 m_pCOPlay1 = new ControlObjectThreadMain( 00066 ControlObject::getControl(ConfigKey("[Channel1]", "play"))); 00067 m_pCOPlay2 = new ControlObjectThreadMain( 00068 ControlObject::getControl(ConfigKey("[Channel2]", "play"))); 00069 m_pCORepeat1 = new ControlObjectThreadMain( 00070 ControlObject::getControl(ConfigKey("[Channel1]", "repeat"))); 00071 m_pCORepeat2 = new ControlObjectThreadMain( 00072 ControlObject::getControl(ConfigKey("[Channel2]", "repeat"))); 00073 m_pCOCrossfader = new ControlObjectThreadMain( 00074 ControlObject::getControl(ConfigKey("[Master]", "crossfader"))); 00075 } 00076 00077 DlgAutoDJ::~DlgAutoDJ() 00078 { 00079 delete m_pCOPlayPos1; 00080 delete m_pCOPlayPos2; 00081 delete m_pCOPlay1; 00082 delete m_pCOPlay2; 00083 delete m_pCORepeat2; 00084 delete m_pCOCrossfader; 00085 } 00086 00087 void DlgAutoDJ::onShow() 00088 { 00089 m_pAutoDJTableModel->select(); 00090 } 00091 00092 void DlgAutoDJ::setup(QDomNode node) 00093 { 00094 00095 QPalette pal = palette(); 00096 00097 // Row colors 00098 if (!WWidget::selectNode(node, "BgColorRowEven").isNull() && 00099 !WWidget::selectNode(node, "BgColorRowUneven").isNull()) { 00100 QColor r1; 00101 r1.setNamedColor(WWidget::selectNodeQString(node, "BgColorRowEven")); 00102 r1 = WSkinColor::getCorrectColor(r1); 00103 QColor r2; 00104 r2.setNamedColor(WWidget::selectNodeQString(node, "BgColorRowUneven")); 00105 r2 = WSkinColor::getCorrectColor(r2); 00106 00107 // For now make text the inverse of the background so it's readable In 00108 // the future this should be configurable from the skin with this as the 00109 // fallback option 00110 QColor text(255 - r1.red(), 255 - r1.green(), 255 - r1.blue()); 00111 00112 //setAlternatingRowColors ( true ); 00113 00114 QColor fgColor; 00115 fgColor.setNamedColor(WWidget::selectNodeQString(node, "FgColor")); 00116 fgColor = WSkinColor::getCorrectColor(fgColor); 00117 00118 pal.setColor(QPalette::Base, r1); 00119 pal.setColor(QPalette::AlternateBase, r2); 00120 pal.setColor(QPalette::Text, text); 00121 pal.setColor(QPalette::WindowText, fgColor); 00122 00123 } 00124 00125 setPalette(pal); 00126 00127 pushButtonAutoDJ->setPalette(pal); 00128 //m_pTrackTableView->setPalette(pal); //Since we're getting this passed into us already created, 00129 //shouldn't need to set the palette. 00130 } 00131 00132 void DlgAutoDJ::onSearchStarting() 00133 { 00134 } 00135 00136 void DlgAutoDJ::onSearchCleared() 00137 { 00138 } 00139 00140 void DlgAutoDJ::onSearch(const QString& text) 00141 { 00142 m_pAutoDJTableModel->search(text); 00143 } 00144 00145 void DlgAutoDJ::loadSelectedTrack() { 00146 m_pTrackTableView->loadSelectedTrack(); 00147 } 00148 00149 void DlgAutoDJ::loadSelectedTrackToGroup(QString group) { 00150 m_pTrackTableView->loadSelectedTrackToGroup(group); 00151 } 00152 00153 void DlgAutoDJ::moveSelection(int delta) { 00154 m_pTrackTableView->moveSelection(delta); 00155 } 00156 00157 void DlgAutoDJ::shufflePlaylist(bool buttonChecked) 00158 { 00159 Q_UNUSED(buttonChecked); 00160 qDebug() << "Shuffling AutoDJ playlist"; 00161 m_pAutoDJTableModel->shuffleTracks(m_pAutoDJTableModel->index(0, 0)); 00162 qDebug() << "Shuffling done"; 00163 } 00164 00165 void DlgAutoDJ::toggleAutoDJ(bool toggle) 00166 { 00167 if (toggle) //Enable Auto DJ 00168 { 00169 if (m_pCOPlay1->get() == 1.0f && m_pCOPlay2->get() == 1.0f) { 00170 qDebug() << "One player must be stopped before enabling Auto DJ mode"; 00171 pushButtonAutoDJ->setChecked(false); 00172 return; 00173 } 00174 00175 pushButtonAutoDJ->setText(tr("Disable Auto DJ")); 00176 m_bAutoDJEnabled = true; 00177 connect(m_pCOPlayPos1, SIGNAL(valueChanged(double)), 00178 this, SLOT(player1PositionChanged(double))); 00179 connect(m_pCOPlayPos2, SIGNAL(valueChanged(double)), 00180 this, SLOT(player2PositionChanged(double))); 00181 00182 00183 //Manually override the "next track is already loaded" flag 00184 //because we've already primed a player with the first track. 00185 //We do this so that you don't lose the first song in your 00186 //Auto DJ queue if you enable Auto DJ then change your mind 00187 //and disable it right away. This just makes it a little bit 00188 //more user friendly. :) 00189 //m_bNextTrackAlreadyLoaded = true; 00190 m_bPlayer1Primed = false; 00191 m_bPlayer2Primed = false; 00192 00193 //If there are no tracks in the Auto DJ queue, disable Auto DJ mode. 00194 /* if (m_pAutoDJTableModel->rowCount() == 0) 00195 { 00196 //Queue was empty. Disable and return. 00197 pushButtonAutoDJ->setChecked(false); 00198 return; 00199 }*/ //don't need this code, above block takes care of this case. 00200 00201 //If only one of the players is playing... 00202 if ((m_pCOPlay1->get() == 1.0f && m_pCOPlay2->get() == 0.0f) || 00203 (m_pCOPlay1->get() == 0.0f && m_pCOPlay2->get() == 1.0f)) 00204 { 00205 //Load the first song from the queue. 00206 if (!loadNextTrackFromQueue(false)) { 00207 //Queue was empty. Disable and return. 00208 pushButtonAutoDJ->setChecked(false); 00209 return; 00210 } 00211 //Set the primed flags so the crossfading algorithm knows 00212 //that it doesn't need to load a track into whatever player. 00213 if (m_pCOPlay1->get() == 1.0f) 00214 { 00215 m_bPlayer1Primed = true; 00216 } 00217 if (m_pCOPlay2->get() == 1.0f) 00218 { 00219 m_bPlayer2Primed = true; 00220 } 00221 } 00222 //If both players are stopped, start the first one (which should have just had a track loaded into it) 00223 else if (m_pCOPlay1->get() == 0.0f && m_pCOPlay2->get() == 0.0f) { 00224 //Load the first song from the queue. 00225 if (!loadNextTrackFromQueue(false)) { 00226 //Queue was empty. Disable and return. 00227 pushButtonAutoDJ->setChecked(false); 00228 return; 00229 } 00230 m_pCOCrossfader->slotSet(-1.0f); //Move crossfader to the left! 00231 m_pCORepeat1->slotSet(1.0f); //Turn on repeat mode to avoid race condition between async load 00232 //and "play" command. 00233 m_pCOPlay1->slotSet(1.0f); //Play the track in player 1 00234 } 00235 } 00236 else //Disable Auto DJ 00237 { 00238 pushButtonAutoDJ->setText(tr("Enable Auto DJ")); 00239 qDebug() << "Auto DJ disabled"; 00240 m_bAutoDJEnabled = false; 00241 m_pCOPlayPos1->disconnect(this); 00242 m_pCOPlayPos2->disconnect(this); 00243 m_pCORepeat1->slotSet(0.0f); //Turn off repeat mode 00244 m_pCORepeat2->slotSet(0.0f); //Turn off repeat mode 00245 } 00246 } 00247 00248 void DlgAutoDJ::player1PositionChanged(double value) 00249 { 00250 const float posThreshold = 0.95; //95% playback is when we crossfade and do stuff 00251 if (value > posThreshold) 00252 { 00253 //Crossfade! 00254 float crossfadeValue = -1.0f + 2*(value-posThreshold)/(1.0f-posThreshold); 00255 m_pCOCrossfader->slotSet(crossfadeValue); //Move crossfader to the right! 00256 //If the second player doesn't have a new track loaded in it... 00257 if (!m_bPlayer2Primed) 00258 { 00259 qDebug() << "pp1c loading"; 00260 00261 //Load the next track into Player 2 00262 //if (!m_bNextTrackAlreadyLoaded) //Fudge to make us not skip the first track 00263 { 00264 if (!loadNextTrackFromQueue(true)) 00265 return; 00266 } 00267 //m_bNextTrackAlreadyLoaded = false; //Reset fudge 00268 m_bPlayer2Primed = true; 00269 } 00270 //If the second player is stopped... 00271 if (m_pCOPlay2->get() == 0.0f) 00272 { 00273 //Turn off repeat mode to tell Player 1 to stop at the end 00274 m_pCORepeat1->slotSet(0.0f); 00275 00276 //Turn on repeat mode to tell Player 2 to start playing when the new track is loaded. 00277 //This helps us get around the fact that it takes time for the track to be loaded 00278 //and that is executed asynchronously (so we get around the race condition). 00279 m_pCORepeat2->slotSet(1.0f); 00280 //Play! 00281 m_pCOPlay2->slotSet(1.0f); 00282 } 00283 00284 if (value == 1.0f) 00285 { 00286 m_pCOPlay1->slotSet(0.0f); //Stop the player 00287 m_bPlayer1Primed = false; 00288 } 00289 } 00290 } 00291 00292 void DlgAutoDJ::player2PositionChanged(double value) 00293 { 00294 const float posThreshold = 0.95; //95% playback is when we crossfade and do stuff 00295 if (value > posThreshold) 00296 { 00297 //Crossfade! 00298 float crossfadeValue = 1.0f - 2*(value-posThreshold)/(1.0f-posThreshold); 00299 m_pCOCrossfader->slotSet(crossfadeValue); //Move crossfader to the right! 00300 00301 //If the first player doesn't have the next track loaded, load a track into 00302 //it and start playing it! 00303 if (!m_bPlayer1Primed) 00304 { 00305 //Load the next track into player 1 00306 //if (!m_bNextTrackAlreadyLoaded) //Fudge to make us not skip the first track 00307 { 00308 if (!loadNextTrackFromQueue(true)) 00309 return; 00310 } 00311 //m_bNextTrackAlreadyLoaded = false; //Reset fudge 00312 m_bPlayer1Primed = true; 00313 } 00314 if (m_pCOPlay1->get() == 0.0f) 00315 { 00316 //Turn off repeat mode to tell Player 2 to stop at the end 00317 m_pCORepeat2->slotSet(0.0f); 00318 00319 //Turn on repeat mode to tell Player 1 to start playing when the new track is loaded. 00320 //This helps us get around the fact that it takes time for the track to be loaded 00321 //and that is executed asynchronously (so we get around the race condition). 00322 m_pCORepeat1->slotSet(1.0f); 00323 m_pCOPlay1->slotSet(1.0f); 00324 } 00325 00326 if (value == 1.0f) 00327 { 00328 m_pCOPlay2->slotSet(0.0f); //Stop the player 00329 m_bPlayer2Primed = false; 00330 } 00331 } 00332 } 00333 00334 00335 bool DlgAutoDJ::loadNextTrackFromQueue(bool removeTopMostBeforeLoading) 00336 { 00337 if (removeTopMostBeforeLoading) { 00338 //Only remove the top track if this isn't the start of Auto DJ mode. 00339 m_pAutoDJTableModel->removeTrack(m_pAutoDJTableModel->index(0, 0)); 00340 } 00341 00342 //Get the track at the top of the playlist... 00343 TrackPointer nextTrack = m_pAutoDJTableModel->getTrack(m_pAutoDJTableModel->index(0, 0)); 00344 00345 if (!nextTrack) //We ran out of tracks in the queue... 00346 { 00347 //Disable auto DJ and return... 00348 pushButtonAutoDJ->setChecked(false); 00349 return false; 00350 } 00351 00352 //m_bNextTrackAlreadyLoaded = false; 00353 00354 emit(loadTrack(nextTrack)); 00355 00356 return true; 00357 }