#include "qtspotifymain.h" #include "logindialog.h" #include #include #include #include #include #include #include #include #include #include #include #include "despotify_cpp.h" Q_DECLARE_METATYPE(playlist *) Q_DECLARE_METATYPE(track *) QtSpotifyMain::QtSpotifyMain(QWidget *parent) : QMainWindow(parent), m_session(0), m_searchResult(0), m_storedPlaylist(0), m_machine(new QStateMachine), m_debugging(false), m_authenticationWatcher(0), m_retrievingPlayListWatcher(0) { initUi(); initWatchers(); initMachine(); } QtSpotifyMain::~QtSpotifyMain() { QSettings settings("qtspotify", "qtspotify"); settings.setValue(QString::fromLatin1("debuggingOutput"), m_ui.actionDebuggingOutput->isChecked()); if (m_session != 0) { endSession(); } } void QtSpotifyMain::initUi() { m_ui.setupUi(this); m_logInDialog = new LogInDialog(this); QSettings settings("qtspotify", "qtspotify"); bool debuggingOutput = settings.value(QString::fromLatin1("debuggingOutput")).toBool(); setDebugging(debuggingOutput); m_ui.actionDebuggingOutput->setChecked(debuggingOutput); connect(m_ui.actionDebuggingOutput, SIGNAL(toggled(bool)), this, SLOT(setDebugging(bool))); QString userName = settings.value(QString::fromLatin1("userName")).toString(); QString password = settings.value(QString::fromLatin1("password")).toString(); if (userName.isEmpty() || password.isEmpty()) { m_logInDialog->setRememberSettings(false); } else { m_logInDialog->setRememberSettings(true); m_logInDialog->setUserName(userName); m_logInDialog->setPassword(password); } setStatusBar(new MyStatusBar(this)); } void QtSpotifyMain::initWatchers() { m_authenticationWatcher = new QFutureWatcher(this); connect(m_authenticationWatcher, SIGNAL(finished()), this, SLOT(decideLoginResult())); m_retrievingPlayListWatcher = new QFutureWatcher(this); connect(m_retrievingPlayListWatcher, SIGNAL(finished()), this, SLOT(populateSearchBox())); } void QtSpotifyMain::retrievePlayLists() { debug(tr("Retrieving playlists")); m_ui.searchComboBox->clear(); m_ui.searchComboBox->clearEditText(); if (m_storedPlaylist != 0) despotify_free_playlist(m_storedPlaylist); QFuture retrieving = QtConcurrent::run(despotify_get_stored_playlists, m_session); m_retrievingPlayListWatcher->setFuture(retrieving); } void QtSpotifyMain::selectPlayList() { QString searchTerm = m_ui.searchComboBox->currentText(); if (m_searchResult != 0) { despotify_free_search(m_searchResult); m_searchResult = 0; } m_ui.playList->clear(); int idx = m_ui.searchComboBox->currentIndex(); if (idx >= 0) { QVariant data = m_ui.searchComboBox->itemData(idx); playlist *pl = data.value(); if (pl != 0) { debug(tr("Selecting playlist '%1'").arg(QString::fromUtf8(pl->name))); setPlayList(pl->tracks); return; } } m_searchResult = despotify_search(m_session, searchTerm.toUtf8().data(), 50); if (m_searchResult != 0) { debug(tr("Searching for '%1'").arg(searchTerm)); setPlayList(m_searchResult->tracks); } else { debug(tr("No results when searching for '%1'").arg(searchTerm)); } } void QtSpotifyMain::populateSearchBox() { debug(tr("Populating search box")); m_storedPlaylist = m_retrievingPlayListWatcher->result(); if (m_storedPlaylist == 0) debug(tr("Cannot get stored playlists, error==%1").arg(QString::fromUtf8(m_session->last_error))); playlist *pl = m_storedPlaylist; while (pl != 0) { m_ui.searchComboBox->addItem(QString::fromUtf8(pl->name), QVariant::fromValue(pl)); debug(tr("Adding '%1'").arg(QString::fromUtf8(pl->name))); pl = pl->next; } m_ui.searchComboBox->setEditText(QString()); } void QtSpotifyMain::stop() { debug(tr("Stopping")); despotify_stop(m_session); } void QtSpotifyMain::pause() { debug(tr("Pausing")); despotify_pause(m_session); } void QtSpotifyMain::resume() { debug(tr("Resuming")); despotify_resume(m_session); } void QtSpotifyMain::play() { if (m_ui.playList->currentItem() == 0) { qWarning("Nothing to play"); return ; } QVariant data = m_ui.playList->currentItem()->data(0, Qt::UserRole); track *t = data.value(); if (t != 0) { debug(tr("Playing '%1'").arg(t->title)); if (!despotify_play(m_session, t, false)) { QMessageBox::information(this, tr("Error when playing track"), tr("Despotify error: %1").arg(QString::fromUtf8(m_session->last_error))); } else { setNewTrack(t); } } else { qWarning("No track connected to current item"); } } void QtSpotifyMain::initPlayingState(QState *playingState) { QState *notPaused = new QState(playingState); notPaused->setObjectName("notPaused"); playingState->setInitialState(notPaused); QState *paused = new QState(playingState); paused->setObjectName("paused"); connect(paused, SIGNAL(entered()), this, SLOT(pause())); connect(paused, SIGNAL(exited()), this, SLOT(resume())); notPaused->addTransition(m_ui.actionPauseOrResume, SIGNAL(triggered()), paused); paused->addTransition(m_ui.actionPauseOrResume, SIGNAL(triggered()), notPaused); } void QtSpotifyMain::decideLoginResult() { if (m_authenticationWatcher->result()) { debug(tr("Login succeeded")); emit loggedIn(); } else { debug(tr("Login failed, error==%1").arg(QString::fromUtf8(m_session->last_error))); emit loginFailed(); } } void QtSpotifyMain::initPlayBackHandlingState(QState *playBackHandlingState) { QState *stoppedState = new QState(playBackHandlingState); stoppedState->assignProperty(m_ui.actionPauseOrResume, "enabled", false); stoppedState->assignProperty(m_ui.actionPlayOrStop, "enabled", true); stoppedState->assignProperty(m_ui.albumLabel, "text", QString()); stoppedState->assignProperty(m_ui.artistLabel, "text", QString()); stoppedState->assignProperty(m_ui.songLabel, "text", QString()); stoppedState->setObjectName("stoppedState"); connect(stoppedState, SIGNAL(entered()), this, SLOT(stop())); playBackHandlingState->setInitialState(stoppedState); QState *playingState = new QState(playBackHandlingState); playingState->setObjectName("playingState"); playingState->assignProperty(m_ui.actionPlayOrStop, "enabled", true); connect(playingState, SIGNAL(entered()), this, SLOT(play())); stoppedState->assignProperty(m_ui.actionPauseOrResume, "enabled", true); initPlayingState(playingState); stoppedState->addTransition(m_ui.actionPlayOrStop, SIGNAL(triggered()), playingState); playingState->addTransition(m_ui.actionPlayOrStop, SIGNAL(triggered()), stoppedState); stoppedState->addTransition(m_ui.playList, SIGNAL(doubleClicked(QModelIndex)), playingState); playingState->addTransition(m_ui.playList, SIGNAL(doubleClicked(QModelIndex)), playingState); } void QtSpotifyMain::initLoggedInState(QState *loggedIn) { QState *playListHandlingState = new QState(loggedIn); playListHandlingState->setObjectName("playListHandlingState"); initPlayListHandlingState(playListHandlingState); QState *playBackHandlingState = new QState(loggedIn); playBackHandlingState->setObjectName("playBackHandlingState"); initPlayBackHandlingState(playBackHandlingState); } void QtSpotifyMain::initPlayListHandlingState(QState *playListHandlingState) { QState *idle = new QState(playListHandlingState); idle->assignProperty(m_ui.actionSearch, "enabled", true); idle->assignProperty(m_ui.searchComboBox, "enabled", true); idle->assignProperty(m_ui.playList, "enabled", true); idle->assignProperty(m_ui.actionRetrieveStoredPlaylists, "enabled", true); idle->setObjectName("idle"); idle->assignProperty(statusBar(), "statusMessage", tr("Go ahead...")); playListHandlingState->setInitialState(idle); QState *requestedRetrieve = new QState(playListHandlingState); requestedRetrieve->assignProperty(m_ui.actionSearch, "enabled", false); requestedRetrieve->assignProperty(m_ui.searchComboBox, "enabled", false); requestedRetrieve->assignProperty(m_ui.playList, "enabled", true); requestedRetrieve->assignProperty(m_ui.actionRetrieveStoredPlaylists, "enabled", false); connect(requestedRetrieve, SIGNAL(entered()), this, SLOT(retrievePlayLists())); requestedRetrieve->setObjectName("requestedRetrieve"); QState *playListSelected = new QState(playListHandlingState); playListSelected->setObjectName("playListSelected"); connect(playListSelected, SIGNAL(entered()), this, SLOT(selectPlayList())); idle->addTransition(m_ui.searchComboBox, SIGNAL(activated(QString)), playListSelected); idle->addTransition(m_ui.actionRetrieveStoredPlaylists, SIGNAL(triggered()), requestedRetrieve); playListSelected->addTransition(idle); requestedRetrieve->addTransition(m_retrievingPlayListWatcher, SIGNAL(finished()), idle); } void QtSpotifyMain::debug(const QString &text) { if (m_debugging) qDebug() << text; } void QtSpotifyMain::initLoggingInState(QState *loggingInState) { QState *logInDialogShown = new QState(loggingInState); connect(logInDialogShown, SIGNAL(entered()), m_logInDialog, SLOT(exec())); logInDialogShown->assignProperty(statusBar(), "statusMessage", tr("Waiting for input")); logInDialogShown->setObjectName("logInDialogShown"); loggingInState->setInitialState(logInDialogShown); QState *logInDialogAccepted = new QState(loggingInState); logInDialogAccepted->assignProperty(statusBar(), "statusMessage", tr("Trying to log in...")); logInDialogAccepted->setObjectName("logInDialogAccepted"); connect(logInDialogAccepted, SIGNAL(entered()), this, SLOT(logIn())); logInDialogShown->addTransition(m_logInDialog, SIGNAL(accepted()), logInDialogAccepted); } void QtSpotifyMain::initMachine() { QState *notLoggedInState = new QState(m_machine); notLoggedInState->assignProperty(m_ui.actionLogIn, "enabled", true); notLoggedInState->assignProperty(m_ui.actionLogOut, "enabled", false); notLoggedInState->assignProperty(m_ui.actionSearch, "enabled", false); notLoggedInState->assignProperty(m_ui.centralwidget, "enabled", false); notLoggedInState->assignProperty(m_ui.actionPauseOrResume, "enabled", false); notLoggedInState->assignProperty(m_ui.actionPlayOrStop, "enabled", false); notLoggedInState->assignProperty(m_ui.actionRetrieveStoredPlaylists, "enabled", false); notLoggedInState->assignProperty(statusBar(), "statusMessage", tr("Not logged in")); notLoggedInState->assignProperty(this, "debuggingMessage", tr("Entered 'notLoggedInState'")); notLoggedInState->setObjectName("notLoggedInState"); m_machine->setInitialState(notLoggedInState); QState *loggingInState = new QState(m_machine); loggingInState->assignProperty(m_ui.actionLogIn, "enabled", false); loggingInState->assignProperty(m_ui.actionLogOut, "enabled", false); loggingInState->assignProperty(m_ui.actionSearch, "enabled", false); loggingInState->assignProperty(m_ui.centralwidget, "enabled", false); loggingInState->assignProperty(m_ui.actionPauseOrResume, "enabled", false); loggingInState->assignProperty(m_ui.actionPlayOrStop, "enabled", false); loggingInState->assignProperty(m_ui.actionRetrieveStoredPlaylists, "enabled", false); loggingInState->setObjectName("loggingInState"); loggingInState->assignProperty(this, "debuggingMessage", tr("Entered 'loggingInState'")); initLoggingInState(loggingInState); QState *loggedInState = new QState(QState::ParallelStates, m_machine); loggedInState->assignProperty(m_ui.actionLogIn, "enabled", false); loggedInState->assignProperty(m_ui.actionLogOut, "enabled", true); loggedInState->assignProperty(m_ui.centralwidget, "enabled", true); loggedInState->setObjectName("loggedInState"); loggedInState->assignProperty(this, "debuggingMessage", tr("Entered 'loggedInState'")); initLoggedInState(loggedInState); notLoggedInState->addTransition(m_ui.actionLogIn, SIGNAL(triggered()), loggingInState); loggingInState->addTransition(m_logInDialog, SIGNAL(rejected()), notLoggedInState); loggingInState->addTransition(this, SIGNAL(loginFailed()), notLoggedInState); loggingInState->addTransition(this, SIGNAL(loggedIn()), loggedInState); m_machine->start(); } void QtSpotifyMain::setPlayList(track *t) { debug(tr("Setting new playlist")); m_ui.playList->clear(); while (t != 0) { QTreeWidgetItem *w = new QTreeWidgetItem(); w->setData(0, Qt::DisplayRole, QString::fromUtf8(t->artist->name)); w->setData(1, Qt::DisplayRole, QString::fromUtf8(t->title)); w->setData(2, Qt::DisplayRole, QString::fromUtf8(t->album)); w->setData(0, Qt::UserRole, QVariant::fromValue(t)); m_ui.playList->addTopLevelItem(w); t = t->next; } } static void callback(despotify_session *session, int signal, void *data, void *callbackData) { if (callbackData == 0 || data == 0 || session == 0) return; switch (signal) { case DESPOTIFY_TRACK_CHANGE: { track *t = reinterpret_cast(data); QtSpotifyMain *qsm = reinterpret_cast(session->client_callback_data); qsm->setNewTrack(t); } }; } void QtSpotifyMain::endSession() { debug("Ending session"); if (m_storedPlaylist != 0) despotify_free_playlist(m_storedPlaylist); if (m_searchResult != 0) { despotify_free_search(m_searchResult); m_searchResult = 0; } m_ui.searchComboBox->clear(); despotify_exit(m_session); } void QtSpotifyMain::logIn() { if (m_session == 0) { m_session = despotify_init_client(callback, this); if (m_session == 0) { emit loginFailed(); return; } } QString userName = m_logInDialog->userName(); QString password = m_logInDialog->password(); QSettings settings("qtspotify", "qtspotify"); if (m_logInDialog->rememberSettings()) { debug("Saving settings"); settings.setValue(QString::fromLatin1("userName"), userName); settings.setValue(QString::fromLatin1("password"), password); } else { debug("Clearing settings"); settings.remove(QString::fromLatin1("userName")); settings.remove(QString::fromLatin1("password")); } debug(tr("Logging in as user '%1'").arg(userName)); QFuture authentication = QtConcurrent::run(despotify_authenticate, m_session, userName.toLocal8Bit(), password.toLocal8Bit()); m_authenticationWatcher->setFuture(authentication); } void QtSpotifyMain::setNewTrack(track *t) { debug(tr("Setting new track '%1'").arg(QString::fromUtf8(t->title))); m_ui.artistLabel->setText(QString::fromUtf8(t->artist->name)); m_ui.albumLabel->setText(QString::fromUtf8(t->album)); m_ui.songLabel->setText(QString::fromUtf8(t->title)); }