From 1e9ab4a54fe53bc09416b90b777abcb998954ab1 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 30 Oct 2009 14:22:52 +0100 Subject: Tabbed UI: Automatically downloads playlists in background Downloads cover art and has "now playing" tab No search at the moment Buggy currently. --- qtspotifymain.cpp | 332 +++++++++++++++++++++++++++++------------------------- 1 file changed, 178 insertions(+), 154 deletions(-) (limited to 'qtspotifymain.cpp') diff --git a/qtspotifymain.cpp b/qtspotifymain.cpp index 32176c6..1e563ec 100644 --- a/qtspotifymain.cpp +++ b/qtspotifymain.cpp @@ -25,6 +25,8 @@ #include "qtspotifymain.h" #include "logindialog.h" #include "qtplaylist.h" +#include "storedplaylistmodel.h" +#include "coverdatabase.h" #include #include @@ -32,6 +34,7 @@ #include #include #include +#include #include #include @@ -41,9 +44,9 @@ #include "despotify_cpp.h" -Q_DECLARE_METATYPE(QtPlaylist *) Q_DECLARE_METATYPE(track *) + namespace { class SelectTrackEvent: public QEvent { @@ -57,15 +60,34 @@ namespace { }; } +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); + QCoreApplication::postEvent(qsm, new SelectTrackEvent(t)); + } + }; +} QtSpotifyMain::QtSpotifyMain(QWidget *parent) - : QMainWindow(parent), m_session(0), m_rootPlaylist(0), - m_machine(new QStateMachine), m_debugging(false), + : QMainWindow(parent), m_session(0), m_machine(new QStateMachine), m_debugging(false), m_authenticationWatcher(0), m_retrievingPlayListWatcher(0) { - initUi(); - initWatchers(); - initMachine(); + m_session = despotify_init_client(callback, this, true); + + if (m_session != 0) { + initUi(); + initWatchers(); + initMachine(); + } else { + qWarning("Couldn't initialize despotify"); + } } QtSpotifyMain::~QtSpotifyMain() @@ -105,6 +127,10 @@ void QtSpotifyMain::initUi() } setStatusBar(new MyStatusBar(this)); + + m_coverDatabase = new CoverDatabase(m_session, this); + connect(m_coverDatabase, SIGNAL(coverLoaded(QPixmap)), + m_ui.coverArtLabel, SLOT(setPixmap(QPixmap))); } void QtSpotifyMain::initWatchers() @@ -135,6 +161,7 @@ void QtSpotifyMain::selectTrack(track *newTrack) track *t = data.value(); if (t == newTrack) { m_ui.playList->setCurrentItem(m_ui.playList->topLevelItem(i)); + setNewTrack(t); return; } } @@ -145,61 +172,34 @@ void QtSpotifyMain::selectTrack(track *newTrack) void QtSpotifyMain::retrievePlayLists() { debug(tr("Retrieving playlists")); - m_ui.searchComboBox->clear(); - m_ui.searchComboBox->clearEditText(); - - if (m_rootPlaylist != 0) { - despotify_free_playlist(m_rootPlaylist); - m_rootPlaylist = 0; - } - QFuture retrieving = QtConcurrent::run(despotify_get_stored_playlists, m_session); m_retrievingPlayListWatcher->setFuture(retrieving); } void QtSpotifyMain::selectPlayList() { - QString searchTerm = m_ui.searchComboBox->currentText(); - m_ui.playList->clear(); + m_ui.playList->clear(); - int idx = m_ui.searchComboBox->currentIndex(); - if (idx >= 0) { - QVariant data = m_ui.searchComboBox->itemData(idx); + QModelIndex idx = m_ui.storedPlaylists->currentIndex(); + if (idx.isValid()) { + QVariant data = idx.data(Qt::UserRole); QtPlaylist *pl = data.value(); if (pl != 0) { - debug(tr("Selecting playlist '%1'").arg(m_ui.searchComboBox->itemText(idx))); + debug(tr("Selecting playlist '%1'").arg(idx.data(Qt::DisplayRole).toString())); setPlaylist(pl->tracks()); return; } } - - QtPlaylist *newSearch = new QtPlaylist(m_session, this); - newSearch->setSearchTerm(searchTerm); - m_searches.append(newSearch); - - debug(tr("Searching for '%1'").arg(searchTerm)); - setPlaylist(newSearch->tracks()); } void QtSpotifyMain::populateSearchBox() { debug(tr("Populating search box")); - m_rootPlaylist = m_retrievingPlayListWatcher->result(); - if (m_rootPlaylist == 0) + playlist *rootPlaylist = m_retrievingPlayListWatcher->result(); + if (rootPlaylist == 0) debug(tr("Cannot get stored playlists, error==%1").arg(QString::fromUtf8(m_session->last_error))); - playlist *pl = m_rootPlaylist; - while (pl != 0) { - QtPlaylist *playlist = new QtPlaylist(m_session, this); - playlist->setPlaylist(pl); - - m_ui.searchComboBox->addItem(QString::fromUtf8(pl->name), QVariant::fromValue(playlist)); - debug(tr("Adding '%1'").arg(QString::fromUtf8(pl->name))); - - pl = pl->next; - } - - m_ui.searchComboBox->setEditText(QString()); + m_ui.storedPlaylists->setModel(new StoredPlaylistModel(m_session, rootPlaylist, m_ui.storedPlaylists)); } void QtSpotifyMain::stop() @@ -245,16 +245,24 @@ void QtSpotifyMain::play() void QtSpotifyMain::initPlayingState(QState *playingState) { QState *notPaused = new QState(playingState); - notPaused->setObjectName("notPaused"); - playingState->setInitialState(notPaused); + { + notPaused->setObjectName("notPaused"); + notPaused->assignProperty(m_ui.playButton, "text", tr("Pause")); + 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())); + { + paused->assignProperty(m_ui.playButton, "text", tr("Play")); + 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); + notPaused->addTransition(m_ui.playButton, SIGNAL(clicked()), paused); + paused->addTransition(m_ui.playButton, SIGNAL(clicked()), notPaused); } void QtSpotifyMain::decideLoginResult() @@ -271,26 +279,35 @@ void QtSpotifyMain::decideLoginResult() 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); + { + 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->assignProperty(m_ui.coverArtLabel, "pixmap", QPixmap()); + stoppedState->assignProperty(m_ui.coverArtLabel, "text", QString()); + stoppedState->assignProperty(m_ui.playButton, "enabled", true); + stoppedState->assignProperty(m_ui.skipSongButton, "enabled", false); + 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); + { + playingState->setObjectName("playingState"); + playingState->assignProperty(m_ui.actionPlayOrStop, "enabled", true); + connect(playingState, SIGNAL(entered()), this, SLOT(play())); + stoppedState->assignProperty(m_ui.actionPauseOrResume, "enabled", true); + stoppedState->assignProperty(m_ui.playButton, "enabled", true); + stoppedState->assignProperty(m_ui.skipSongButton, "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)), @@ -300,47 +317,67 @@ void QtSpotifyMain::initPlayBackHandlingState(QState *playBackHandlingState) void QtSpotifyMain::initLoggedInState(QState *loggedIn) { QState *playListHandlingState = new QState(loggedIn); - playListHandlingState->setObjectName("playListHandlingState"); - initPlayListHandlingState(playListHandlingState); + { + playListHandlingState->setObjectName("playListHandlingState"); + initPlayListHandlingState(playListHandlingState); + } QState *playBackHandlingState = new QState(loggedIn); - playBackHandlingState->setObjectName("playBackHandlingState"); - initPlayBackHandlingState(playBackHandlingState); + { + playBackHandlingState->setObjectName("playBackHandlingState"); + initPlayBackHandlingState(playBackHandlingState); + } +} + +void QtSpotifyMain::initIdleState(QState *idle) +{ + QState *requestedRetrieve = new QState(idle); + { + requestedRetrieve->assignProperty(m_ui.storedPlaylists, "enabled", false); + connect(requestedRetrieve, SIGNAL(entered()), this, SLOT(retrievePlayLists())); + requestedRetrieve->setObjectName("requestedRetrieve"); + } + + QHistoryState *historyState = new QHistoryState(idle); + { + historyState->setDefaultState(requestedRetrieve); + idle->setInitialState(historyState); + } + + QState *retrieved = new QState(idle); + { + retrieved->assignProperty(m_ui.storedPlaylists, "enabled", true); + retrieved->setObjectName("retrieved"); + } + + requestedRetrieve->addTransition(m_retrievingPlayListWatcher, SIGNAL(finished()), retrieved); } 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); - requestedRetrieve->assignProperty(statusBar(), "statusMessage", tr("Retrieving playlists")); - connect(requestedRetrieve, SIGNAL(entered()), this, SLOT(retrievePlayLists())); - requestedRetrieve->setObjectName("requestedRetrieve"); + { + idle->setObjectName("idle"); - QState *playListSelected = new QState(playListHandlingState); - playListSelected->setObjectName("playListSelected"); - playListSelected->assignProperty(statusBar(), "statusMessage", tr("Fetching playlist contents")); - connect(playListSelected, SIGNAL(entered()), this, SLOT(selectPlayList())); + idle->assignProperty(m_ui.actionSearch, "enabled", true); + idle->assignProperty(m_ui.playList, "enabled", true); + idle->assignProperty(statusBar(), "statusMessage", tr("Go ahead...")); - idle->addTransition(m_ui.searchComboBox, SIGNAL(activated(QString)), - playListSelected); - idle->addTransition(m_ui.actionRetrieveStoredPlaylists, SIGNAL(triggered()), - requestedRetrieve); + initIdleState(idle); + playListHandlingState->setInitialState(idle); + } + QState *playListSelected = new QState(playListHandlingState); + { + playListSelected->setObjectName("playListSelected"); + playListSelected->assignProperty(statusBar(), "statusMessage", tr("Fetching playlist contents")); + connect(playListSelected, SIGNAL(entered()), this, SLOT(selectPlayList())); + } + + idle->addTransition(m_ui.storedPlaylists, SIGNAL(activated(QModelIndex)), playListSelected); playListSelected->addTransition(idle); - requestedRetrieve->addTransition(m_retrievingPlayListWatcher, SIGNAL(finished()), idle); + } void QtSpotifyMain::debug(const QString &text) @@ -352,15 +389,19 @@ void QtSpotifyMain::debug(const QString &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); + { + 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())); + { + 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); } @@ -368,37 +409,45 @@ void QtSpotifyMain::initLoggingInState(QState *loggingInState) 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); + { + notLoggedInState->assignProperty(m_ui.actionLogIn, "enabled", true); + + 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(statusBar(), "statusMessage", tr("Select 'log in' from menu to log 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); + { + loggingInState->assignProperty(m_ui.actionLogIn, "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->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); + { + loggedInState->assignProperty(m_ui.actionLogIn, "enabled", false); + 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); @@ -424,47 +473,19 @@ void QtSpotifyMain::setPlaylist(QList tracks) } } -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); - QCoreApplication::postEvent(qsm, new SelectTrackEvent(t)); - } - }; -} void QtSpotifyMain::endSession() { debug("Ending session"); - if (m_rootPlaylist != 0) - despotify_free_playlist(m_rootPlaylist); - qDeleteAll(m_searches); - - for (int i=0; icount(); ++i) { - QVariant v = m_ui.searchComboBox->itemData(i); - QtPlaylist *pl = v.value(); - delete pl; - } - m_ui.searchComboBox->clear(); - despotify_exit(m_session); } void QtSpotifyMain::logIn() { if (m_session == 0) { - m_session = despotify_init_client(callback, this, true); - if (m_session == 0) { - emit loginFailed(); - return; - } + emit loginFailed(); + return; } QString userName = m_logInDialog->userName(); @@ -493,6 +514,9 @@ 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.albumLabel->setText(QLatin1Char('(') + QString::fromUtf8(t->album) + QLatin1Char(')')); m_ui.songLabel->setText(QString::fromUtf8(t->title)); + m_ui.coverArtLabel->setPixmap(QPixmap()); + m_ui.coverArtLabel->setText(QString()); + m_coverDatabase->loadCover(reinterpret_cast(t->cover_id)); } -- cgit v1.2.3