diff options
author | Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@nokia.com> | 2009-10-23 21:06:09 +0200 |
---|---|---|
committer | Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@nokia.com> | 2009-10-23 21:06:09 +0200 |
commit | 95fc9a918f123ec165f1048aa5ea8b522a4a806a (patch) | |
tree | 3a778fa417c954920fbf54071abde912236ace43 |
First commit
-rw-r--r-- | despotify_cpp.h | 8 | ||||
-rw-r--r-- | logindialog.cpp | 57 | ||||
-rw-r--r-- | logindialog.h | 31 | ||||
-rw-r--r-- | logindialog.ui | 95 | ||||
-rw-r--r-- | main.cpp | 26 | ||||
-rw-r--r-- | qtspotify.pro | 9 | ||||
-rw-r--r-- | qtspotify.ui | 236 | ||||
-rw-r--r-- | qtspotifymain.cpp | 431 | ||||
-rw-r--r-- | qtspotifymain.h | 106 |
9 files changed, 999 insertions, 0 deletions
diff --git a/despotify_cpp.h b/despotify_cpp.h new file mode 100644 index 0000000..8027d92 --- /dev/null +++ b/despotify_cpp.h @@ -0,0 +1,8 @@ +#ifndef DESPOTIFY_CPP_H +#define DESPOTIFY_CPP_H + +extern "C" { + #include <despotify.h> +} + +#endif // DESPOTIFY_CPP_H diff --git a/logindialog.cpp b/logindialog.cpp new file mode 100644 index 0000000..28feb50 --- /dev/null +++ b/logindialog.cpp @@ -0,0 +1,57 @@ +#include "logindialog.h" +#include "ui_logindialog.h" + +LogInDialog::LogInDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::LogInDialog) +{ + ui->setupUi(this); +} + +LogInDialog::~LogInDialog() +{ + delete ui; +} + +void LogInDialog::changeEvent(QEvent *e) +{ + QDialog::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } +} + +QString LogInDialog::userName() const +{ + return ui->userNameLineEdit->text(); +} + +QString LogInDialog::password() const +{ + return ui->passwordLineEdit->text(); +} + +bool LogInDialog::rememberSettings() const +{ + return ui->rememberMe->isChecked(); +} + +void LogInDialog::setUserName(const QString &userName) +{ + ui->userNameLineEdit->setText(userName); +} + +void LogInDialog::setPassword(const QString &password) +{ + ui->passwordLineEdit->setText(password); +} + +void LogInDialog::setRememberSettings(bool on) +{ + ui->rememberMe->setChecked(on); +} + diff --git a/logindialog.h b/logindialog.h new file mode 100644 index 0000000..4c2b9a5 --- /dev/null +++ b/logindialog.h @@ -0,0 +1,31 @@ +#ifndef LOGINDIALOG_H +#define LOGINDIALOG_H + +#include <QDialog> + +namespace Ui { + class LogInDialog; +} + +class LogInDialog : public QDialog { + Q_OBJECT +public: + LogInDialog(QWidget *parent = 0); + ~LogInDialog(); + + QString userName() const; + QString password() const; + bool rememberSettings() const; + + void setUserName(const QString &userName); + void setPassword(const QString &password); + void setRememberSettings(bool on); + +protected: + void changeEvent(QEvent *e); + +private: + Ui::LogInDialog *ui; +}; + +#endif // LOGINDIALOG_H diff --git a/logindialog.ui b/logindialog.ui new file mode 100644 index 0000000..516ab43 --- /dev/null +++ b/logindialog.ui @@ -0,0 +1,95 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>LogInDialog</class> + <widget class="QDialog" name="LogInDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>165</height> + </rect> + </property> + <property name="windowTitle"> + <string>Enter log in details (premium account)</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>User name:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="userNameLineEdit"/> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Password</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="passwordLineEdit"> + <property name="echoMode"> + <enum>QLineEdit::PasswordEchoOnEdit</enum> + </property> + </widget> + </item> + <item row="4" column="0" colspan="2"> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QCheckBox" name="rememberMe"> + <property name="text"> + <string>Remember password (stored in clear text)</string> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>LogInDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>LogInDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..1522118 --- /dev/null +++ b/main.cpp @@ -0,0 +1,26 @@ +#include "qtspotifymain.h" + +#include "despotify_cpp.h" + +int main(int argc, char **argv) +{ + if (!despotify_init()) { + qWarning("Couldn't initialize despotify"); + return 1; + } + + QApplication app(argc, argv); + + QtSpotifyMain qsm; + qsm.showMaximized(); + + int ret = app.exec(); + + if (!despotify_cleanup()) { + qWarning("Couldn't clean up despotify"); + return 2; + } + + return ret; +} + diff --git a/qtspotify.pro b/qtspotify.pro new file mode 100644 index 0000000..b284ff0 --- /dev/null +++ b/qtspotify.pro @@ -0,0 +1,9 @@ +HEADERS += qtspotifymain.h \ + logindialog.h \ + despotify_cpp.h +SOURCES += qtspotifymain.cpp \ + main.cpp \ + logindialog.cpp +FORMS += qtspotify.ui \ + logindialog.ui +LIBS += -ldespotify diff --git a/qtspotify.ui b/qtspotify.ui new file mode 100644 index 0000000..6f665b0 --- /dev/null +++ b/qtspotify.ui @@ -0,0 +1,236 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>QtSpotifyMain</class> + <widget class="QMainWindow" name="QtSpotifyMain"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>340</width> + <height>680</height> + </rect> + </property> + <property name="windowTitle"> + <string>Qt Despotify Client</string> + </property> + <widget class="QWidget" name="centralwidget"> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="artistLabel"> + <property name="toolTip"> + <string>Currently playing artist</string> + </property> + <property name="text"> + <string>Artist</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLabel" name="songLabel"> + <property name="toolTip"> + <string>Currently playing song</string> + </property> + <property name="text"> + <string>Song</string> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QLabel" name="albumLabel"> + <property name="toolTip"> + <string>Currently playing album</string> + </property> + <property name="text"> + <string>Album</string> + </property> + </widget> + </item> + <item row="1" column="0" colspan="3"> + <widget class="QTreeWidget" name="playList"> + <column> + <property name="text"> + <string>Artist</string> + </property> + </column> + <column> + <property name="text"> + <string>Song</string> + </property> + </column> + <column> + <property name="text"> + <string>Album</string> + </property> + </column> + </widget> + </item> + <item row="2" column="0" colspan="3"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Search:</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="searchComboBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Select playlist or enter search term</string> + </property> + <property name="editable"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <widget class="QMenuBar" name="menubar"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>340</width> + <height>24</height> + </rect> + </property> + <widget class="QMenu" name="menu_File"> + <property name="title"> + <string>&File</string> + </property> + <addaction name="actionLogIn"/> + <addaction name="actionDebuggingOutput"/> + <addaction name="separator"/> + <addaction name="actionExit"/> + </widget> + <widget class="QMenu" name="menuPlaylist"> + <property name="title"> + <string>&Playlist</string> + </property> + <addaction name="actionSearch"/> + <addaction name="actionRetrieveStoredPlaylists"/> + </widget> + <widget class="QMenu" name="menuPlayback"> + <property name="title"> + <string>Playback</string> + </property> + <addaction name="actionPlayOrStop"/> + <addaction name="actionPauseOrResume"/> + </widget> + <addaction name="menu_File"/> + <addaction name="menuPlaylist"/> + <addaction name="menuPlayback"/> + </widget> + <widget class="QStatusBar" name="statusbar"/> + <action name="actionLogIn"> + <property name="text"> + <string>&Log in...</string> + </property> + <property name="shortcut"> + <string>Ctrl+L</string> + </property> + </action> + <action name="actionExit"> + <property name="text"> + <string>E&xit</string> + </property> + <property name="shortcut"> + <string>Alt+X, Ctrl+Q</string> + </property> + </action> + <action name="actionSearch"> + <property name="text"> + <string>Search</string> + </property> + <property name="shortcut"> + <string>Ctrl+S</string> + </property> + </action> + <action name="actionLogOut"> + <property name="text"> + <string>Log &out</string> + </property> + <property name="shortcut"> + <string>Ctrl+X</string> + </property> + </action> + <action name="actionPlayOrStop"> + <property name="text"> + <string>&Play / stop</string> + </property> + <property name="shortcut"> + <string>Backspace</string> + </property> + </action> + <action name="actionPauseOrResume"> + <property name="text"> + <string>P&ause / resume</string> + </property> + <property name="shortcut"> + <string>Space</string> + </property> + </action> + <action name="actionRetrieveStoredPlaylists"> + <property name="text"> + <string>&Retrieve stored playlists</string> + </property> + <property name="shortcut"> + <string>Ctrl+R</string> + </property> + </action> + <action name="actionDebuggingOutput"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="checked"> + <bool>true</bool> + </property> + <property name="text"> + <string>Debugging output</string> + </property> + </action> + </widget> + <resources/> + <connections> + <connection> + <sender>actionExit</sender> + <signal>triggered()</signal> + <receiver>QtSpotifyMain</receiver> + <slot>close()</slot> + <hints> + <hint type="sourcelabel"> + <x>-1</x> + <y>-1</y> + </hint> + <hint type="destinationlabel"> + <x>399</x> + <y>299</y> + </hint> + </hints> + </connection> + <connection> + <sender>actionSearch</sender> + <signal>triggered()</signal> + <receiver>searchComboBox</receiver> + <slot>setFocus()</slot> + <hints> + <hint type="sourcelabel"> + <x>-1</x> + <y>-1</y> + </hint> + <hint type="destinationlabel"> + <x>195</x> + <y>641</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/qtspotifymain.cpp b/qtspotifymain.cpp new file mode 100644 index 0000000..af8e2a2 --- /dev/null +++ b/qtspotifymain.cpp @@ -0,0 +1,431 @@ +#include "qtspotifymain.h" +#include "logindialog.h" + +#include <QtCore/QtConcurrentRun> +#include <QtCore/QFuture> +#include <QtCore/QFutureWatcher> +#include <QtCore/QStateMachine> +#include <QtCore/QState> +#include <QtCore/QSettings> + +#include <QtGui/QMenuBar> +#include <QtGui/QMenu> +#include <QtGui/QMessageBox> +#include <QtGui/QGridLayout> +#include <QtGui/QInputDialog> + +#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<bool>(this); + connect(m_authenticationWatcher, SIGNAL(finished()), this, SLOT(decideLoginResult())); + + m_retrievingPlayListWatcher = new QFutureWatcher<playlist *>(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<playlist *> 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<playlist *>(); + 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<track *>(); + 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<track *>(data); + QtSpotifyMain *qsm = reinterpret_cast<QtSpotifyMain*>(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<bool> 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)); +} diff --git a/qtspotifymain.h b/qtspotifymain.h new file mode 100644 index 0000000..69f2bfb --- /dev/null +++ b/qtspotifymain.h @@ -0,0 +1,106 @@ +#ifndef QTSPOTIFYMAIN_H +#define QTSPOTIFYMAIN_H + +#include "ui_qtspotify.h" + +#include <QtGui/QMainWindow> + +#include <QtCore/QFuture> +#include <QtCore/QFutureWatcher> + +class MyStatusBar: public QStatusBar +{ + Q_OBJECT + Q_PROPERTY(QString statusMessage READ statusMessage WRITE setStatusMessage); +public: + MyStatusBar(QWidget *parent = 0) : QStatusBar(parent) + { + m_label = new QLabel(); + addPermanentWidget(m_label); + } + + void setStatusMessage(const QString &text) + { + m_label->setText(text); + } + + QString statusMessage() const + { + return m_label->text(); + } + +private: + QLabel *m_label; +}; + +struct despotify_session; +struct track; +struct playlist; +struct search_result; + +class QStateMachine; +class QState; + +class LogInDialog; +class QtSpotifyMain: public QMainWindow +{ + Q_OBJECT + Q_PROPERTY(QString debuggingMessage READ debuggingMessage WRITE debug) +public: + QtSpotifyMain(QWidget *parent = 0); + ~QtSpotifyMain(); + + void setNewTrack(track *t); + + // Just a dummy so we can use the property mechanism to call the debug() function + QString debuggingMessage() const { return QString(); } + + bool debugging() const { return m_debugging; } + +private slots: + void logIn(); + void endSession(); + void retrievePlayLists(); + void populateSearchBox(); + void play(); + void pause(); + void stop(); + void resume(); + void selectPlayList(); + void decideLoginResult(); + void debug(const QString &text); + void setDebugging(bool on) { m_debugging = on; } + +signals: + void loggedIn(); + void loginFailed(); + +private: + void setPlayList(track *t); + + void initUi(); + void initWatchers(); + + void initMachine(); + void initLoggingInState(QState *); + void initLoggedInState(QState *); + void initPlayListHandlingState(QState *); + void initPlayBackHandlingState(QState *); + void initPlayingState(QState *); + + Ui_QtSpotifyMain m_ui; + despotify_session *m_session; + search_result *m_searchResult; + playlist *m_storedPlaylist; + QStateMachine *m_machine; + + bool m_debugging; + + QFutureWatcher<bool> *m_authenticationWatcher; + QFutureWatcher<playlist *> *m_retrievingPlayListWatcher; + + LogInDialog *m_logInDialog; + +}; + +#endif // QTSPOTIFYMAIN_H |