From abf19c9f66679f053f26d02157acbcdff7e9e2de Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 30 Oct 2009 17:55:14 +0100 Subject: Implemented skip/previous song and searches --- qtspotify.pro | 11 +++-- qtspotify.ui | 40 ++++++++++++++++-- qtspotifymain.cpp | 123 +++++++++++++++++++++++++++++++++++++++++++++++------- qtspotifymain.h | 7 ++++ searchdialog.cpp | 56 +++++++++++++++++++++++++ searchdialog.h | 49 ++++++++++++++++++++++ searchdialog.ui | 74 ++++++++++++++++++++++++++++++++ searchmodel.cpp | 62 +++++++++++++++++++++++++++ searchmodel.h | 51 ++++++++++++++++++++++ 9 files changed, 452 insertions(+), 21 deletions(-) create mode 100644 searchdialog.cpp create mode 100644 searchdialog.h create mode 100644 searchdialog.ui create mode 100644 searchmodel.cpp create mode 100644 searchmodel.h diff --git a/qtspotify.pro b/qtspotify.pro index 711d738..061cbe5 100644 --- a/qtspotify.pro +++ b/qtspotify.pro @@ -3,13 +3,18 @@ HEADERS += qtspotifymain.h \ despotify_cpp.h \ qtplaylist.h \ storedplaylistmodel.h \ - coverdatabase.h + coverdatabase.h \ + searchdialog.h \ + searchmodel.h SOURCES += qtspotifymain.cpp \ main.cpp \ logindialog.cpp \ qtplaylist.cpp \ storedplaylistmodel.cpp \ - coverdatabase.cpp + coverdatabase.cpp \ + searchdialog.cpp \ + searchmodel.cpp FORMS += qtspotify.ui \ - logindialog.ui + logindialog.ui \ + searchdialog.ui LIBS += -ldespotify diff --git a/qtspotify.ui b/qtspotify.ui index 773af59..7be2d8e 100644 --- a/qtspotify.ui +++ b/qtspotify.ui @@ -18,7 +18,7 @@ - 2 + 1 @@ -80,8 +80,35 @@ Searches - - + + + + + + + + + Search more + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + @@ -163,6 +190,13 @@ + + + + Previous + + + diff --git a/qtspotifymain.cpp b/qtspotifymain.cpp index 0fb4750..9b9186f 100644 --- a/qtspotifymain.cpp +++ b/qtspotifymain.cpp @@ -27,6 +27,8 @@ #include "qtplaylist.h" #include "storedplaylistmodel.h" #include "coverdatabase.h" +#include "searchdialog.h" +#include "searchmodel.h" #include #include @@ -99,7 +101,6 @@ QtSpotifyMain::~QtSpotifyMain() if (m_session != 0) { endSession(); } - } void QtSpotifyMain::initUi() @@ -128,9 +129,49 @@ void QtSpotifyMain::initUi() setStatusBar(new MyStatusBar(this)); + m_ui.searchListView->setModel(new SearchModel(m_session, m_ui.searchListView)); + m_coverDatabase = new CoverDatabase(m_session, this); connect(m_coverDatabase, SIGNAL(coverLoaded(QPixmap)), m_ui.coverArtLabel, SLOT(setPixmap(QPixmap))); + + connect(m_ui.actionSearch, SIGNAL(triggered()), this, SLOT(search())); + connect(m_ui.skipSongButton, SIGNAL(clicked()), this, SLOT(skip())); + connect(m_ui.previousButton, SIGNAL(clicked()), this, SLOT(previous())); + connect(m_ui.playList, SIGNAL(doubleClicked(QModelIndex)), + this, SIGNAL(playlistItemActivated())); +} + +void QtSpotifyMain::skip() +{ + QTreeWidgetItem *item = m_ui.playList->currentItem(); + if (item == 0) + return; + + int idx = m_ui.playList->indexOfTopLevelItem(item); + if (idx < 0) + return; + + if (++idx >= m_ui.playList->topLevelItemCount()) + return; + + m_ui.playList->setCurrentItem(m_ui.playList->topLevelItem(idx)); + + emit playlistItemActivated(); +} + +void QtSpotifyMain::previous() +{ + QTreeWidgetItem *item = m_ui.playList->currentItem(); + if (item == 0) + return; + + int idx = m_ui.playList->indexOfTopLevelItem(item) - 1; + if (idx < 0) + return; + + m_ui.playList->setCurrentItem(m_ui.playList->topLevelItem(idx)); + emit playlistItemActivated(); } void QtSpotifyMain::initWatchers() @@ -176,11 +217,11 @@ void QtSpotifyMain::retrievePlayLists() m_retrievingPlayListWatcher->setFuture(retrieving); } -void QtSpotifyMain::selectPlayList() +void QtSpotifyMain::selectSearchOrPlaylist(QListView *listView) { - m_ui.playList->clear(); + m_ui.playList->clear(); - QModelIndex idx = m_ui.storedPlaylists->currentIndex(); + QModelIndex idx = listView->currentIndex(); if (idx.isValid()) { QVariant data = idx.data(Qt::UserRole); QtPlaylist *pl = data.value(); @@ -189,7 +230,20 @@ void QtSpotifyMain::selectPlayList() setPlaylist(pl->tracks()); return; } + } else { + debug(tr("Selected playlist index is not valid")); } + +} + +void QtSpotifyMain::selectPlayList() +{ + selectSearchOrPlaylist(m_ui.storedPlaylists); +} + +void QtSpotifyMain::selectSearch() +{ + selectSearchOrPlaylist(m_ui.searchListView); } void QtSpotifyMain::populateSearchBox() @@ -202,6 +256,23 @@ void QtSpotifyMain::populateSearchBox() m_ui.storedPlaylists->setModel(new StoredPlaylistModel(m_session, rootPlaylist, m_ui.storedPlaylists)); } +void QtSpotifyMain::search() +{ + SearchDialog searchDialog; + if (searchDialog.exec() == QDialog::Accepted) { + QString searchTerm = searchDialog.searchTerm(); + if (!searchTerm.isEmpty()) { + QAbstractItemModel *model = m_ui.searchListView->model(); + SearchModel *searchModel = qobject_cast(model); + if (searchModel != 0) { + searchModel->addSearch(searchTerm); + m_ui.searchListView->setCurrentIndex(searchModel->index(searchModel->rowCount()-1)); + emit searched(); + } + } + } +} + void QtSpotifyMain::stop() { debug(tr("Stopping")); @@ -233,8 +304,8 @@ void QtSpotifyMain::play() 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)) { + debug(tr("Playing '%1'").arg(t->title)); + if (!despotify_play(m_session, t, true)) { QMessageBox::information(this, tr("Error when playing track"), tr("Despotify error: %1").arg(QString::fromUtf8(m_session->last_error))); } else { @@ -290,6 +361,7 @@ void QtSpotifyMain::initPlayBackHandlingState(QState *playBackHandlingState) stoppedState->assignProperty(m_ui.coverArtLabel, "text", QString()); stoppedState->assignProperty(m_ui.playButton, "enabled", true); stoppedState->assignProperty(m_ui.skipSongButton, "enabled", false); + stoppedState->assignProperty(m_ui.previousButton, "enabled", false); stoppedState->setObjectName("stoppedState"); connect(stoppedState, SIGNAL(entered()), this, SLOT(stop())); playBackHandlingState->setInitialState(stoppedState); @@ -302,13 +374,14 @@ void QtSpotifyMain::initPlayBackHandlingState(QState *playBackHandlingState) connect(playingState, SIGNAL(entered()), this, SLOT(play())); playingState->assignProperty(m_ui.playButton, "enabled", true); playingState->assignProperty(m_ui.skipSongButton, "enabled", true); + playingState->assignProperty(m_ui.previousButton, "enabled", false); initPlayingState(playingState); } - stoppedState->addTransition(m_ui.playList, SIGNAL(doubleClicked(QModelIndex)), - playingState); - playingState->addTransition(m_ui.playList, SIGNAL(doubleClicked(QModelIndex)), - playingState); + stoppedState->addTransition(this, SIGNAL(playlistItemActivated()), + playingState); + playingState->addTransition(this, SIGNAL(playlistItemActivated()), + playingState); } void QtSpotifyMain::initLoggedInState(QState *loggedIn) @@ -331,6 +404,9 @@ void QtSpotifyMain::initIdleState(QState *idle) QState *requestedRetrieve = new QState(idle); { requestedRetrieve->assignProperty(m_ui.storedPlaylists, "enabled", false); + requestedRetrieve->assignProperty(m_ui.searchListView, "enabled", false); + requestedRetrieve->assignProperty(m_ui.actionSearch, "enabled", false); + requestedRetrieve->assignProperty(statusBar(), "statusMessage", tr("Retrieving playlists, please wait...")); connect(requestedRetrieve, SIGNAL(entered()), this, SLOT(retrievePlayLists())); requestedRetrieve->setObjectName("requestedRetrieve"); } @@ -344,6 +420,9 @@ void QtSpotifyMain::initIdleState(QState *idle) QState *retrieved = new QState(idle); { retrieved->assignProperty(m_ui.storedPlaylists, "enabled", true); + retrieved->assignProperty(m_ui.searchListView, "enabled", true); + retrieved->assignProperty(m_ui.actionSearch, "enabled", true); + retrieved->assignProperty(statusBar(), "statusMessage", tr("Go ahead")); retrieved->setObjectName("retrieved"); } @@ -358,7 +437,6 @@ void QtSpotifyMain::initPlayListHandlingState(QState *playListHandlingState) idle->assignProperty(m_ui.actionSearch, "enabled", true); idle->assignProperty(m_ui.playList, "enabled", true); - idle->assignProperty(statusBar(), "statusMessage", tr("Go ahead...")); initIdleState(idle); playListHandlingState->setInitialState(idle); @@ -371,9 +449,19 @@ void QtSpotifyMain::initPlayListHandlingState(QState *playListHandlingState) connect(playListSelected, SIGNAL(entered()), this, SLOT(selectPlayList())); } + QState *searchSelected = new QState(playListHandlingState); + { + searchSelected->setObjectName("searchSelected"); + searchSelected->assignProperty(statusBar(), "statusMessage", tr("Searching...")); + connect(searchSelected, SIGNAL(entered()), this, SLOT(selectSearch())); + } + idle->addTransition(m_ui.storedPlaylists, SIGNAL(activated(QModelIndex)), playListSelected); - playListSelected->addTransition(idle); + idle->addTransition(m_ui.searchListView, SIGNAL(activated(QModelIndex)), searchSelected); + idle->addTransition(this, SIGNAL(searched()), searchSelected); + playListSelected->addTransition(idle); + searchSelected->addTransition(idle); } @@ -414,9 +502,7 @@ void QtSpotifyMain::initMachine() 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); + notLoggedInState->setObjectName("notLoggedInState"); } QState *loggingInState = new QState(m_machine); @@ -429,6 +515,7 @@ void QtSpotifyMain::initMachine() loggingInState->assignProperty(this, "debuggingMessage", tr("Entered 'loggingInState'")); initLoggingInState(loggingInState); + m_machine->setInitialState(loggingInState); } QState *loggedInState = new QState(QState::ParallelStates, m_machine); @@ -462,6 +549,12 @@ void QtSpotifyMain::setPlaylist(QList tracks) w->setData(2, Qt::DisplayRole, QString::fromUtf8(t->album)); w->setData(0, Qt::UserRole, QVariant::fromValue(t)); + QFont font = m_ui.playList->font(); + font.setUnderline(true); + + w->setFont(0, font); + w->setFont(2, font); + m_ui.playList->addTopLevelItem(w); } } diff --git a/qtspotifymain.h b/qtspotifymain.h index f4b11b0..4078179 100644 --- a/qtspotifymain.h +++ b/qtspotifymain.h @@ -95,13 +95,19 @@ private slots: void stop(); void resume(); void selectPlayList(); + void selectSearch(); void decideLoginResult(); void debug(const QString &text); void setDebugging(bool on) { m_debugging = on; } + void search(); + void skip(); + void previous(); signals: void loggedIn(); void loginFailed(); + void searched(); + void playlistItemActivated(); private: void setPlaylist(QList tracks); @@ -118,6 +124,7 @@ private: void initIdleState(QState *); void setNewTrack(track *t); void selectTrack(track *t); + void selectSearchOrPlaylist(QListView *listView); Ui_QtSpotifyMain m_ui; despotify_session *m_session; diff --git a/searchdialog.cpp b/searchdialog.cpp new file mode 100644 index 0000000..39b5314 --- /dev/null +++ b/searchdialog.cpp @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "searchdialog.h" +#include "ui_searchdialog.h" + +SearchDialog::SearchDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::SearchDialog) +{ + ui->setupUi(this); +} + +SearchDialog::~SearchDialog() +{ + delete ui; +} + +void SearchDialog::changeEvent(QEvent *e) +{ + QDialog::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } +} + +QString SearchDialog::searchTerm() const +{ + return ui->searchLineEdit->text(); +} + diff --git a/searchdialog.h b/searchdialog.h new file mode 100644 index 0000000..a264163 --- /dev/null +++ b/searchdialog.h @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef SEARCHDIALOG_H +#define SEARCHDIALOG_H + +#include + +namespace Ui { + class SearchDialog; +} + +class SearchDialog : public QDialog { + Q_OBJECT +public: + SearchDialog(QWidget *parent = 0); + ~SearchDialog(); + + QString searchTerm() const; + +protected: + void changeEvent(QEvent *e); + +private: + Ui::SearchDialog *ui; +}; + +#endif // SEARCHDIALOG_H diff --git a/searchdialog.ui b/searchdialog.ui new file mode 100644 index 0000000..d154e0d --- /dev/null +++ b/searchdialog.ui @@ -0,0 +1,74 @@ + + + SearchDialog + + + + 0 + 0 + 400 + 83 + + + + Search + + + + + + Search for: + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + SearchDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + SearchDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/searchmodel.cpp b/searchmodel.cpp new file mode 100644 index 0000000..4988c56 --- /dev/null +++ b/searchmodel.cpp @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "searchmodel.h" +#include "qtplaylist.h" + +SearchModel::SearchModel(despotify_session *session, QObject *parent) + : QAbstractListModel(parent), m_session(session) +{ +} + +int SearchModel::rowCount(const QModelIndex &parent) const +{ + Q_ASSERT(!parent.isValid()); + return m_playlists.size(); +} + +QVariant SearchModel::data(const QModelIndex &index, int role) const +{ + Q_ASSERT(index.column() == 0); + if (role == Qt::DisplayRole) + return m_playlists.at(index.row())->name(); + else if (role == Qt::UserRole) + return QVariant::fromValue(m_playlists.at(index.row())); + + return QVariant(); +} + +void SearchModel::addSearch(const QString &searchTerm) +{ + beginInsertRows(QModelIndex(), m_playlists.size(), m_playlists.size()); + + QtPlaylist *playlist = new QtPlaylist(m_session, this); + playlist->setSearchTerm(searchTerm); + m_playlists.append(playlist); + + endInsertRows(); + + emit searchAdded(searchTerm); +} + diff --git a/searchmodel.h b/searchmodel.h new file mode 100644 index 0000000..856b37e --- /dev/null +++ b/searchmodel.h @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef SEARCHMODEL_H +#define SEARCHMODEL_H + +#include + +struct despotify_session; +class QtPlaylist; +class SearchModel: public QAbstractListModel +{ + Q_OBJECT +public: + SearchModel(despotify_session *session, QObject *parent = 0); + + int rowCount(const QModelIndex &parent = QModelIndex()) const; + QVariant data(const QModelIndex &index, int role) const; + + void addSearch(const QString &searchTerm); + +signals: + void searchAdded(const QString &searchTerm); + +private: + QList m_playlists; + despotify_session *m_session; +}; + +#endif // SEARCHMODEL_H -- cgit v1.2.3