summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--qtspotify.pro11
-rw-r--r--qtspotify.ui40
-rw-r--r--qtspotifymain.cpp123
-rw-r--r--qtspotifymain.h7
-rw-r--r--searchdialog.cpp56
-rw-r--r--searchdialog.h49
-rw-r--r--searchdialog.ui74
-rw-r--r--searchmodel.cpp62
-rw-r--r--searchmodel.h51
9 files changed, 452 insertions, 21 deletions
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 @@
<item row="0" column="0">
<widget class="QTabWidget" name="topLevelTabs">
<property name="currentIndex">
- <number>2</number>
+ <number>1</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
@@ -80,8 +80,35 @@
<string>Searches</string>
</property>
<layout class="QGridLayout" name="gridLayout_5">
- <item row="0" column="0">
- <widget class="QListView" name="listView"/>
+ <item row="0" column="0" colspan="2">
+ <widget class="QListView" name="searchListView"/>
+ </item>
+ <item row="1" column="1">
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QPushButton" name="searchMoreButton">
+ <property name="text">
+ <string>Search more</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="2" column="0">
+ <layout class="QHBoxLayout" name="horizontalLayout_2"/>
</item>
</layout>
</widget>
@@ -164,6 +191,13 @@
</spacer>
</item>
<item>
+ <widget class="QPushButton" name="previousButton">
+ <property name="text">
+ <string>Previous</string>
+ </property>
+ </widget>
+ </item>
+ <item>
<widget class="QPushButton" name="playButton">
<property name="text">
<string>Play</string>
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 <QtCore/QtConcurrentRun>
#include <QtCore/QFuture>
@@ -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<QtPlaylist *>();
@@ -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<SearchModel *>(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<track *>();
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<track *> 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<track *> 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 <QDialog>
+
+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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SearchDialog</class>
+ <widget class="QDialog" name="SearchDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>83</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Search</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Search for:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="searchLineEdit"/>
+ </item>
+ <item row="1" 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>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>SearchDialog</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>SearchDialog</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/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 <QAbstractListModel>
+
+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<QtPlaylist *> m_playlists;
+ despotify_session *m_session;
+};
+
+#endif // SEARCHMODEL_H