From 06852aaeb7b382b23e6b3dbf9e70b178cf97b93f Mon Sep 17 00:00:00 2001 From: David Sansome Date: Thu, 28 Apr 2011 17:50:45 +0000 Subject: [PATCH] Show spotify search results in a separate playlist tab rather than in a tree in the sidebar. --- data/data.qrc | 4 + data/icons/22x22/edit-find.png | Bin 0 -> 942 bytes data/icons/32x32/edit-find.png | Bin 0 -> 1705 bytes data/icons/48x48/edit-find.png | Bin 0 -> 3136 bytes data/schema/schema-33.sql | 3 + .../digitallyimported-radio/servicebase.py | 2 +- src/CMakeLists.txt | 2 + src/core/database.cpp | 2 +- src/core/player.cpp | 8 +- src/core/player.h | 8 +- src/playlist/playlist.cpp | 4 +- src/playlist/playlist.h | 6 ++ src/playlist/playlistbackend.cpp | 15 ++- src/playlist/playlistbackend.h | 6 +- src/playlist/playlistcontainer.cpp | 36 ++++++-- src/playlist/playlistcontainer.ui | 2 +- src/playlist/playlistmanager.cpp | 52 +++++++++-- src/playlist/playlistmanager.h | 20 +++- src/playlist/playlisttabbar.cpp | 4 +- src/playlist/playlisttabbar.h | 4 +- src/playlist/playlistview.cpp | 5 +- src/playlist/specialplaylisttype.cpp | 43 +++++++++ src/playlist/specialplaylisttype.h | 48 ++++++++++ src/radio/lastfmservice.cpp | 2 +- src/radio/magnatuneservice.cpp | 2 +- src/radio/somafmservice.cpp | 2 +- src/radio/spotifysearchplaylisttype.cpp | 50 ++++++++++ src/radio/spotifysearchplaylisttype.h | 44 +++++++++ src/radio/spotifyservice.cpp | 86 ++++++++---------- src/radio/spotifyservice.h | 30 +++--- src/scripting/python/player.sip | 4 +- src/smartplaylists/searchpreview.cpp | 2 +- 32 files changed, 383 insertions(+), 113 deletions(-) create mode 100644 data/icons/22x22/edit-find.png create mode 100644 data/icons/32x32/edit-find.png create mode 100644 data/icons/48x48/edit-find.png create mode 100644 data/schema/schema-33.sql create mode 100644 src/playlist/specialplaylisttype.cpp create mode 100644 src/playlist/specialplaylisttype.h create mode 100644 src/radio/spotifysearchplaylisttype.cpp create mode 100644 src/radio/spotifysearchplaylisttype.h diff --git a/data/data.qrc b/data/data.qrc index 3db07f0ae..757b80473 100644 --- a/data/data.qrc +++ b/data/data.qrc @@ -314,5 +314,9 @@ schema/schema-30.sql schema/schema-31.sql schema/schema-32.sql + icons/22x22/edit-find.png + icons/32x32/edit-find.png + icons/48x48/edit-find.png + schema/schema-33.sql diff --git a/data/icons/22x22/edit-find.png b/data/icons/22x22/edit-find.png new file mode 100644 index 0000000000000000000000000000000000000000..1b7a252803dd641279df3e3644458dfd6236afea GIT binary patch literal 942 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H3?x5i&EW)6%*9TgAsieWw;%dH0CG7CJR*yM z%CCbkqm#z$3ZS55iEBhjaDG}zd16s2LwR|*US?i)adKios$PCk`s{Z$QVa}?O9FgC zT>t<74^)o{^z`)f_4UQX#H6I81Ox;y6+lFUgoN1H*#!j!S;2srnHfkkGBU!|17(41 zCMG7JxB?ge)c{3AL_~mw14&U)Q9eFCYinyA9UXHpu(!82G&FQ}b`A*%DJ?Ap8Xg=R z6dDq2V`kLd-RSSjPM}?~qWp4la`Hl4K)s5Jib_gK$^r~3QetXqYPvFly1Kds>WXFxd=?fK zc6N4-j*c!0%U$yCFn9H*sG>^ z7^Ed7rU$uZCMV>WFy`my7lgT$xGR=hFjcsSR#a3}$2!+I^46pV)YsQHH#fJowsv-Q zc6D|2_4Q3iFqtr6!sN-5XC+zAO14^3p4n_7CO&R(@<-PWx;b{;r*{OsAY=Pz8ke&_znS06ro{rdg; zkDot({`&p<&!4}4|Neu5#9LdY08@aLr;B4q#jULqe1i@dFt}Y-$yHq9p&P()s^Rep z>6<%>j6Je_FSw5#w+*J9U$hD`;NseM zwr8a(R@OxN$NqiSD(}y#mh$M!(tK@UCS$jM0`)!|2bav(mKN*26Ro{|Q;}6_%kSb4 zUF&H+Ezj-QSBEYvJMC(`n?FG(V(S5)mg0$LoDXhLj1^SoOuLv-vzh19+00_0zGK_p wPh=~}x@si1{vex^?&HbFf0{ks_A>q>tI>mI%Ql^-pq$Cz>FVdQ&MBb@0Ez8GlK=n! literal 0 HcmV?d00001 diff --git a/data/icons/32x32/edit-find.png b/data/icons/32x32/edit-find.png new file mode 100644 index 0000000000000000000000000000000000000000..9b3fe6bca06c7147d5dc79a2a2ae506d8fd03c9b GIT binary patch literal 1705 zcmV;a23GlrP)$x}9)U-ug zo3sy{CMQ9h%edX7L%Fta}YW=Y(#ro z8v=6z$aFYyPgA~6gG z6KpmIJRTn^DypC&B6>y#pT~>5oLm@mdSp4BXliW4mhK*$K6whW%FEf3wEZaoGJaKM z)q_ie7ctO(9B zy~qCNl-RdtFD{%rk1HQvMt*+&&y-902Le$OqWV8LK7i&`%`8*6GMyAePl2V-QbG#I zt&mY`VYS#%SGNEs1_p5M%vsb_&x4N9bL!}{4D0)p_zbTPRh5<8g1S07F?jw0LPJ9@ zJwt#jc5WbWpRIRSXBSqHZ2n?DG%7Ww@TMSXY9iz^ITw@?aB_P|`sK@(2b-E!!EUod ztyDjgTq4dOq86|td2s&$oH_j=u95bVc`SHDSS#`+_-W5ogEzmk+T-87;%z=SVUPlyU`E!uHlSY^Fu^ zZrzH*@4kntSFWOmdV=7kx5NSg~@1u%VvQ;cLwr&UV5%Y zE;VUw%{*3xl#qysh;0nr^g12LQj4&#$b)r@1L$pOKyP~!s>_QJJ0%u63P`&gnpQTV zVR=1NL?9_K@g{9d-?1y*yZaq9Q#m|YZq6q)IR$0|12-eZqS9=vUsgjg>(R5i0p*3c zFw_#hVwAQp+aGAv!P6#Mt? zgO-|c?AWpXsHmu=tmNIByK(&ees0e&8;#H^9OcLAgx!h{|y% zIy!pwZ=Fon?NYJiu2P|V=y7|3Y||>I^WjdOh(*R}XteRs>JnmuHw{Y+Q&FXkhcP3C z>zfd&Wl$#(p*VdK>KPu^+7r>2FGg=pI+~2JL?|95W*Jxi3FF6CJ@0UdiHULXVt6o$ zli?RdVWBP#>)k^1&YX_TZUHtqr(*kT203O8H{v07o9%nHQ7V)P=y50GM1=yE>-4x- z!{A7X7^{iE{IUXW0%%$$yufihMwpt49G8_8orKOT0gjZ)Fj%d@U_g$eMWlphI%ayZ z*m4bpkh58(P@=Y~9Ni^)ob(HEtyYbXDnvL^oQA%ZWys6RV-KRQhE4wLsd$~0x4Eto z-QH9jE1HfgbJh4HAjYXhS?FBT2=bvOPMXQRz%Y!H_WR(xKoyQ{+knrG?7+2weK_2= z1#>FOVX;_lum{zP5+EB*UH&!2MDO|*4DQ>4F9!DD)BZi^Y-xhq=?p5B%D^*Qacpet zM1x+xvnV&`R^d$F!&&(`59~(W4LXub|KaD>D3{aepb`JZWHQ~S=6qCCP;fibYCRPe z78W<$2g&Fs2>F*VhA@sWfe<$GRXjrAe@Ea~RCL2hbp@SQ00000NkvXXu0mjf61x&k literal 0 HcmV?d00001 diff --git a/data/icons/48x48/edit-find.png b/data/icons/48x48/edit-find.png new file mode 100644 index 0000000000000000000000000000000000000000..bb95091ce096d7fa81b53bd5daff11e39ded2508 GIT binary patch literal 3136 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 aH}+q;z}hXufKbH%0000 const char* Database::kDatabaseFilename = "clementine.db"; -const int Database::kSchemaVersion = 32; +const int Database::kSchemaVersion = 33; const char* Database::kMagicAllSongsTables = "%allsongstables"; int Database::sNextConnectionId = 1; diff --git a/src/core/player.cpp b/src/core/player.cpp index 48c7905af..2e8e7b448 100644 --- a/src/core/player.cpp +++ b/src/core/player.cpp @@ -481,7 +481,7 @@ void Player::InvalidSongRequested(const QUrl& url) { NextItem(Engine::Auto); } -void Player::AddUrlHandler(UrlHandler* handler) { +void Player::RegisterUrlHandler(UrlHandler* handler) { const QString scheme = handler->scheme(); if (url_handlers_.contains(scheme)) { @@ -497,15 +497,15 @@ void Player::AddUrlHandler(UrlHandler* handler) { SLOT(HandleLoadResult(UrlHandler::LoadResult))); } -void Player::RemoveUrlHandler(UrlHandler* handler) { +void Player::UnregisterUrlHandler(UrlHandler* handler) { const QString scheme = url_handlers_.key(handler); if (scheme.isEmpty()) { - qLog(Warning) << "Tried to remove a URL handler for" << handler->scheme() + qLog(Warning) << "Tried to unregister a URL handler for" << handler->scheme() << "that wasn't registered"; return; } - qLog(Info) << "Removed URL handler for" << scheme; + qLog(Info) << "Unregistered URL handler for" << scheme; url_handlers_.remove(scheme); disconnect(handler, SIGNAL(destroyed(QObject*)), this, SLOT(UrlHandlerDestroyed(QObject*))); disconnect(handler, SIGNAL(AsyncLoadComplete(UrlHandler::LoadResult)), diff --git a/src/core/player.h b/src/core/player.h index 7d5839f9d..0b22e5953 100644 --- a/src/core/player.h +++ b/src/core/player.h @@ -50,8 +50,8 @@ public: virtual PlaylistItemPtr GetItemAt(int pos) const = 0; virtual PlaylistManagerInterface* playlists() const = 0; - virtual void AddUrlHandler(UrlHandler* handler) = 0; - virtual void RemoveUrlHandler(UrlHandler* handler) = 0; + virtual void RegisterUrlHandler(UrlHandler* handler) = 0; + virtual void UnregisterUrlHandler(UrlHandler* handler) = 0; public slots: virtual void ReloadSettings() = 0; @@ -119,8 +119,8 @@ public: PlaylistItemPtr GetItemAt(int pos) const; PlaylistManagerInterface* playlists() const { return playlists_; } - void AddUrlHandler(UrlHandler* handler); - void RemoveUrlHandler(UrlHandler* handler); + void RegisterUrlHandler(UrlHandler* handler); + void UnregisterUrlHandler(UrlHandler* handler); public slots: void ReloadSettings(); diff --git a/src/playlist/playlist.cpp b/src/playlist/playlist.cpp index 69dd79eae..4304a2773 100644 --- a/src/playlist/playlist.cpp +++ b/src/playlist/playlist.cpp @@ -80,6 +80,7 @@ Playlist::Playlist(PlaylistBackend* backend, TaskManager* task_manager, LibraryBackend* library, int id, + const QString& special_type, QObject *parent) : QAbstractListModel(parent), is_loading_(false), @@ -97,7 +98,8 @@ Playlist::Playlist(PlaylistBackend* backend, have_incremented_playcount_(false), playlist_sequence_(NULL), ignore_sorting_(false), - undo_stack_(new QUndoStack(this)) + undo_stack_(new QUndoStack(this)), + special_type_(special_type) { undo_stack_->setUndoLimit(kUndoStackSize); diff --git a/src/playlist/playlist.h b/src/playlist/playlist.h index b9f645aa8..054563fab 100644 --- a/src/playlist/playlist.h +++ b/src/playlist/playlist.h @@ -73,6 +73,7 @@ class Playlist : public QAbstractListModel { TaskManager* task_manager, LibraryBackend* library, int id, + const QString& special_type = QString(), QObject* parent = 0); ~Playlist(); @@ -168,6 +169,9 @@ class Playlist : public QAbstractListModel { bool stop_after_current() const; bool is_dynamic() const { return dynamic_playlist_; } + QString special_type() const { return special_type_; } + void set_special_type(const QString& v) { special_type_ = v; } + const PlaylistItemPtr& item_at(int index) const { return items_[index]; } const bool has_item_at(int index) const { return index >= 0 && index < rowCount(); } @@ -368,6 +372,8 @@ class Playlist : public QAbstractListModel { ColumnAlignmentMap column_alignments_; QList veto_listeners_; + + QString special_type_; }; QDataStream& operator <<(QDataStream&, const Playlist*); diff --git a/src/playlist/playlistbackend.cpp b/src/playlist/playlistbackend.cpp index 1da313dda..651fba7c1 100644 --- a/src/playlist/playlistbackend.cpp +++ b/src/playlist/playlistbackend.cpp @@ -57,7 +57,8 @@ PlaylistBackend::PlaylistList PlaylistBackend::GetAllPlaylists() { PlaylistList ret; QSqlQuery q("SELECT ROWID, name, last_played, dynamic_playlist_type," - " dynamic_playlist_data, dynamic_playlist_backend" + " dynamic_playlist_data, dynamic_playlist_backend," + " special_type" " FROM playlists" " ORDER BY ui_order", db); q.exec(); @@ -72,6 +73,7 @@ PlaylistBackend::PlaylistList PlaylistBackend::GetAllPlaylists() { p.dynamic_type = q.value(3).toString(); p.dynamic_data = q.value(4).toByteArray(); p.dynamic_backend = q.value(5).toString(); + p.special_type = q.value(6).toString(); ret << p; } @@ -83,7 +85,8 @@ PlaylistBackend::Playlist PlaylistBackend::GetPlaylist(int id) { QSqlDatabase db(db_->Connect()); QSqlQuery q("SELECT ROWID, name, last_played, dynamic_playlist_type," - " dynamic_playlist_data, dynamic_playlist_backend" + " dynamic_playlist_data, dynamic_playlist_backend," + " special_type" " FROM playlists" " WHERE ROWID=:id", db); q.bindValue(":id", id); @@ -100,6 +103,7 @@ PlaylistBackend::Playlist PlaylistBackend::GetPlaylist(int id) { p.dynamic_type = q.value(3).toString(); p.dynamic_data = q.value(4).toByteArray(); p.dynamic_backend = q.value(5).toString(); + p.special_type = q.value(6).toString(); return p; } @@ -268,12 +272,15 @@ void PlaylistBackend::SavePlaylist(int playlist, const PlaylistItemList& items, transaction.Commit(); } -int PlaylistBackend::CreatePlaylist(const QString &name) { +int PlaylistBackend::CreatePlaylist(const QString &name, + const QString& special_type) { QMutexLocker l(db_->Mutex()); QSqlDatabase db(db_->Connect()); - QSqlQuery q("INSERT INTO playlists (name) VALUES (:name)", db); + QSqlQuery q("INSERT INTO playlists (name, special_type)" + " VALUES (:name, :special_type)", db); q.bindValue(":name", name); + q.bindValue(":special_type", special_type); q.exec(); if (db_->CheckErrors(q)) return -1; diff --git a/src/playlist/playlistbackend.h b/src/playlist/playlistbackend.h index 0f3bea83b..9e4d94cfe 100644 --- a/src/playlist/playlistbackend.h +++ b/src/playlist/playlistbackend.h @@ -46,6 +46,10 @@ class PlaylistBackend : public QObject { QString dynamic_type; QString dynamic_backend; QByteArray dynamic_data; + + // Special playlists have different behaviour, eg. the "spotify-search" + // type has a spotify search box at the top, replacing the ordinary filter. + QString special_type; }; typedef QList PlaylistList; typedef QFuture PlaylistItemFuture; @@ -58,7 +62,7 @@ class PlaylistBackend : public QObject { void SetPlaylistOrder(const QList& ids); - int CreatePlaylist(const QString& name); + int CreatePlaylist(const QString& name, const QString& special_type); void SavePlaylistAsync(int playlist, const PlaylistItemList& items, int last_played, smart_playlists::GeneratorPtr dynamic); void RenamePlaylist(int id, const QString& new_name); diff --git a/src/playlist/playlistcontainer.cpp b/src/playlist/playlistcontainer.cpp index e131dacac..ea381d514 100644 --- a/src/playlist/playlistcontainer.cpp +++ b/src/playlist/playlistcontainer.cpp @@ -17,6 +17,7 @@ #include "playlistcontainer.h" #include "playlistmanager.h" +#include "specialplaylisttype.h" #include "ui_playlistcontainer.h" #include "playlistparsers/playlistparser.h" #include "ui/iconloader.h" @@ -181,6 +182,12 @@ void PlaylistContainer::SetViewModel(Playlist* playlist) { ui_->redo->setDefaultAction(redo_); emit UndoRedoActionsChanged(undo_, redo_); + + // Implement special playlist behaviour + const SpecialPlaylistType* type = manager_->GetPlaylistType(playlist->special_type()); + ui_->filter->set_hint(type->search_hint_text(playlist)); + + } void PlaylistContainer::ActivePlaying() { @@ -207,8 +214,12 @@ void PlaylistContainer::UpdateActiveIcon(const QIcon& icon) { } void PlaylistContainer::PlaylistAdded(int id, const QString &name) { - int index = ui_->tab_bar->count(); - ui_->tab_bar->InsertTab(id, index, name); + Playlist* playlist = manager_->playlist(id); + const SpecialPlaylistType* type = manager_->GetPlaylistType(playlist->special_type()); + + const int index = ui_->tab_bar->count(); + const QIcon icon = type->icon(playlist); + ui_->tab_bar->InsertTab(id, index, name, icon); // Are we startup up, should we select this tab? if (starting_up_ && settings_.value("current_playlist", 1).toInt() == id) { @@ -336,15 +347,22 @@ void PlaylistContainer::SetTabBarHeight(int height) { } void PlaylistContainer::UpdateFilter() { - manager_->current()->proxy()->setFilterFixedString(filter_->text()); - ui_->playlist->JumpToCurrentlyPlayingTrack(); + Playlist* playlist = manager_->current(); + SpecialPlaylistType* type = manager_->GetPlaylistType(playlist->special_type()); - bool no_matches = manager_->current()->proxy()->rowCount() == 0 && - manager_->current()->rowCount() > 0; + if (type->has_special_search_behaviour(playlist)) { + type->Search(filter_->text(), playlist); + } else { + manager_->current()->proxy()->setFilterFixedString(filter_->text()); + ui_->playlist->JumpToCurrentlyPlayingTrack(); - if (no_matches) - RepositionNoMatchesLabel(true); - no_matches_label_->setVisible(no_matches); + const bool no_matches = manager_->current()->proxy()->rowCount() == 0 && + manager_->current()->rowCount() > 0; + + if (no_matches) + RepositionNoMatchesLabel(true); + no_matches_label_->setVisible(no_matches); + } } void PlaylistContainer::resizeEvent(QResizeEvent* e) { diff --git a/src/playlist/playlistcontainer.ui b/src/playlist/playlistcontainer.ui index 90ea4d5fc..842961805 100644 --- a/src/playlist/playlistcontainer.ui +++ b/src/playlist/playlistcontainer.ui @@ -114,7 +114,7 @@ - Playlist search + diff --git a/src/playlist/playlistmanager.cpp b/src/playlist/playlistmanager.cpp index 66de5c974..0e6ba4f83 100644 --- a/src/playlist/playlistmanager.cpp +++ b/src/playlist/playlistmanager.cpp @@ -18,6 +18,8 @@ #include "playlist.h" #include "playlistbackend.h" #include "playlistmanager.h" +#include "specialplaylisttype.h" +#include "core/logging.h" #include "core/songloader.h" #include "core/utilities.h" #include "library/librarybackend.h" @@ -37,6 +39,7 @@ PlaylistManager::PlaylistManager(TaskManager* task_manager, QObject *parent) library_backend_(NULL), sequence_(NULL), parser_(NULL), + default_playlist_type_(new DefaultPlaylistType), current_(-1), active_(-1) { @@ -46,6 +49,9 @@ PlaylistManager::~PlaylistManager() { foreach (const Data& data, playlists_.values()) { delete data.p; } + + qDeleteAll(special_playlist_types_.values()); + delete default_playlist_type_; } void PlaylistManager::Init(LibraryBackend* library_backend, @@ -60,7 +66,7 @@ void PlaylistManager::Init(LibraryBackend* library_backend, connect(library_backend_, SIGNAL(SongsStatisticsChanged(SongList)), SLOT(SongsDiscovered(SongList))); foreach (const PlaylistBackend::Playlist& p, playlist_backend->GetAllPlaylists()) { - AddPlaylist(p.id, p.name); + AddPlaylist(p.id, p.name, p.special_type); } // If no playlist exists then make a new one @@ -85,8 +91,9 @@ const QItemSelection& PlaylistManager::selection(int id) const { return it->selection; } -Playlist* PlaylistManager::AddPlaylist(int id, const QString& name) { - Playlist* ret = new Playlist(playlist_backend_, task_manager_, library_backend_, id); +Playlist* PlaylistManager::AddPlaylist(int id, const QString& name, + const QString& special_type) { + Playlist* ret = new Playlist(playlist_backend_, task_manager_, library_backend_, id, special_type); ret->set_sequence(sequence_); connect(ret, SIGNAL(CurrentSongChanged(Song)), SIGNAL(CurrentSongChanged(Song))); @@ -110,16 +117,17 @@ Playlist* PlaylistManager::AddPlaylist(int id, const QString& name) { return ret; } -void PlaylistManager::New(const QString& name, const SongList& songs) { +void PlaylistManager::New(const QString& name, const SongList& songs, + const QString& special_type) { if (name.isNull()) return; - int id = playlist_backend_->CreatePlaylist(name); + int id = playlist_backend_->CreatePlaylist(name, special_type); if (id == -1) qFatal("Couldn't create playlist"); - Playlist* playlist = AddPlaylist(id, name); + Playlist* playlist = AddPlaylist(id, name, special_type); playlist->InsertSongsOrLibraryItems(songs); SetCurrentPlaylist(id); @@ -390,3 +398,35 @@ QString PlaylistManager::GetNameForNewPlaylist(const SongList& songs) { return result; } + +void PlaylistManager::RegisterSpecialPlaylistType(SpecialPlaylistType* type) { + const QString name = type->name(); + + if (special_playlist_types_.contains(name)) { + qLog(Warning) << "Tried to register a special playlist type" << name + << "but one was already registered"; + return; + } + + qLog(Info) << "Registered special playlist type" << name; + special_playlist_types_.insert(name, type); +} + +void PlaylistManager::UnregisterSpecialPlaylistType(SpecialPlaylistType* type) { + const QString name = special_playlist_types_.key(type); + if (name.isEmpty()) { + qLog(Warning) << "Tried to unregister a special playlist type" << type->name() + << "that wasn't registered"; + return; + } + + qLog(Info) << "Unregistered special playlist type" << name; + special_playlist_types_.remove(name); +} + +SpecialPlaylistType* PlaylistManager::GetPlaylistType(const QString& type) const { + if (special_playlist_types_.contains(type)) { + return special_playlist_types_[type]; + } + return default_playlist_type_; +} diff --git a/src/playlist/playlistmanager.h b/src/playlist/playlistmanager.h index fe4847eba..519a7dfa8 100644 --- a/src/playlist/playlistmanager.h +++ b/src/playlist/playlistmanager.h @@ -31,6 +31,7 @@ class Playlist; class PlaylistBackend; class PlaylistParser; class PlaylistSequence; +class SpecialPlaylistType; class TaskManager; class QModelIndex; @@ -69,8 +70,13 @@ public: virtual PlaylistSequence* sequence() const = 0; virtual PlaylistParser* parser() const = 0; + virtual void RegisterSpecialPlaylistType(SpecialPlaylistType* type) = 0; + virtual void UnregisterSpecialPlaylistType(SpecialPlaylistType* type) = 0; + virtual SpecialPlaylistType* GetPlaylistType(const QString& type) const = 0; + public slots: - virtual void New(const QString& name, const SongList& songs = SongList()) = 0; + virtual void New(const QString& name, const SongList& songs = SongList(), + const QString& special_type = QString()) = 0; virtual void Load(const QString& filename) = 0; virtual void Save(int id, const QString& filename) = 0; virtual void Rename(int id, const QString& new_name) = 0; @@ -161,8 +167,13 @@ public: PlaylistSequence* sequence() const { return sequence_; } PlaylistParser* parser() const { return parser_; } + void RegisterSpecialPlaylistType(SpecialPlaylistType* type); + void UnregisterSpecialPlaylistType(SpecialPlaylistType* type); + SpecialPlaylistType* GetPlaylistType(const QString& type) const; + public slots: - void New(const QString& name, const SongList& songs = SongList()); + void New(const QString& name, const SongList& songs = SongList(), + const QString& special_type = QString()); void Load(const QString& filename); void Save(int id, const QString& filename); void Rename(int id, const QString& new_name); @@ -198,7 +209,7 @@ private slots: void LoadFinished(bool success); private: - Playlist* AddPlaylist(int id, const QString& name); + Playlist* AddPlaylist(int id, const QString& name, const QString& special_type); private: struct Data { @@ -217,6 +228,9 @@ private: // key = id QMap playlists_; + QMap special_playlist_types_; + SpecialPlaylistType* default_playlist_type_; + int current_; int active_; }; diff --git a/src/playlist/playlisttabbar.cpp b/src/playlist/playlisttabbar.cpp index a62d9b7ac..8575e8c67 100644 --- a/src/playlist/playlisttabbar.cpp +++ b/src/playlist/playlisttabbar.cpp @@ -204,11 +204,13 @@ void PlaylistTabBar::CurrentIndexChanged(int index) { emit CurrentIdChanged(tabData(index).toInt()); } -void PlaylistTabBar::InsertTab(int id, int index, const QString& text) { +void PlaylistTabBar::InsertTab(int id, int index, const QString& text, + const QIcon& icon) { suppress_current_changed_ = true; insertTab(index, text); setTabData(index, id); setTabToolTip(index, text); + setTabIcon(index, icon); suppress_current_changed_ = false; if (currentIndex() == index) diff --git a/src/playlist/playlisttabbar.h b/src/playlist/playlisttabbar.h index fb84f7f60..2a20b9130 100644 --- a/src/playlist/playlisttabbar.h +++ b/src/playlist/playlisttabbar.h @@ -19,6 +19,7 @@ #define PLAYLISTTABBAR_H #include +#include #include class PlaylistManager; @@ -49,7 +50,8 @@ public: void set_text_by_id(int id, const QString& text); void RemoveTab(int id); - void InsertTab(int id, int index, const QString& text); + void InsertTab(int id, int index, const QString& text, + const QIcon& icon = QIcon()); signals: void CurrentIdChanged(int id); diff --git a/src/playlist/playlistview.cpp b/src/playlist/playlistview.cpp index 9c8a89f0a..e93f68677 100644 --- a/src/playlist/playlistview.cpp +++ b/src/playlist/playlistview.cpp @@ -16,11 +16,10 @@ */ #include "dynamicplaylistcontrols.h" -#include "playlistview.h" #include "playlist.h" -#include "playlistheader.h" #include "playlistdelegates.h" -#include "playlist.h" +#include "playlistheader.h" +#include "playlistview.h" #include #include diff --git a/src/playlist/specialplaylisttype.cpp b/src/playlist/specialplaylisttype.cpp new file mode 100644 index 000000000..ef4e026aa --- /dev/null +++ b/src/playlist/specialplaylisttype.cpp @@ -0,0 +1,43 @@ +/* This file is part of Clementine. + Copyright 2010, David Sansome + + Clementine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Clementine is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Clementine. If not, see . +*/ + +#include "specialplaylisttype.h" + +#include + +QIcon SpecialPlaylistType::icon(Playlist* playlist) const { + return QIcon(); +} + +QString SpecialPlaylistType::search_hint_text(Playlist* playlist) const { + return QObject::tr("Playlist search"); +} + +QString SpecialPlaylistType::empty_playlist_text(Playlist* playlist) const { + return QString(); +} + +QString SpecialPlaylistType::playlist_view_css(Playlist* playlist) const { + return QString(); +} + +bool SpecialPlaylistType::has_special_search_behaviour(Playlist* playlist) const { + return false; +} + +void SpecialPlaylistType::Search(const QString& text, Playlist* playlist) { +} diff --git a/src/playlist/specialplaylisttype.h b/src/playlist/specialplaylisttype.h new file mode 100644 index 000000000..a3278ed94 --- /dev/null +++ b/src/playlist/specialplaylisttype.h @@ -0,0 +1,48 @@ +/* This file is part of Clementine. + Copyright 2010, David Sansome + + Clementine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Clementine is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Clementine. If not, see . +*/ + +#ifndef SPECIALPLAYLISTTYPE_H +#define SPECIALPLAYLISTTYPE_H + +#include +#include + +class Playlist; + + +class SpecialPlaylistType { +public: + virtual ~SpecialPlaylistType() {} + + virtual QString name() const = 0; + + virtual QIcon icon(Playlist* playlist) const; + virtual QString search_hint_text(Playlist* playlist) const; + virtual QString empty_playlist_text(Playlist* playlist) const; + virtual QString playlist_view_css(Playlist* playlist) const; + + virtual bool has_special_search_behaviour(Playlist* playlist) const; + virtual void Search(const QString& text, Playlist* playlist); +}; + + +class DefaultPlaylistType : public SpecialPlaylistType { +public: + virtual QString name() const { return QString(); } +}; + +#endif // SPECIALPLAYLISTTYPE_H diff --git a/src/radio/lastfmservice.cpp b/src/radio/lastfmservice.cpp index 2d8eced86..b2b9c786a 100644 --- a/src/radio/lastfmservice.cpp +++ b/src/radio/lastfmservice.cpp @@ -103,7 +103,7 @@ LastFMService::LastFMService(RadioModel* parent) add_tag_action_->setEnabled(false); add_custom_action_->setEnabled(false); - model()->player()->AddUrlHandler(url_handler_); + model()->player()->RegisterUrlHandler(url_handler_); } LastFMService::~LastFMService() { diff --git a/src/radio/magnatuneservice.cpp b/src/radio/magnatuneservice.cpp index bf5675b52..a8ef32af8 100644 --- a/src/radio/magnatuneservice.cpp +++ b/src/radio/magnatuneservice.cpp @@ -93,7 +93,7 @@ MagnatuneService::MagnatuneService(RadioModel* parent) library_sort_model_->setDynamicSortFilter(true); library_sort_model_->sort(0); - model()->player()->AddUrlHandler(url_handler_); + model()->player()->RegisterUrlHandler(url_handler_); } MagnatuneService::~MagnatuneService() { diff --git a/src/radio/somafmservice.cpp b/src/radio/somafmservice.cpp index 652dfee8a..b49294327 100644 --- a/src/radio/somafmservice.cpp +++ b/src/radio/somafmservice.cpp @@ -44,7 +44,7 @@ SomaFMService::SomaFMService(RadioModel* parent) get_channels_task_id_(0), network_(new NetworkAccessManager(this)) { - model()->player()->AddUrlHandler(url_handler_); + model()->player()->RegisterUrlHandler(url_handler_); } SomaFMService::~SomaFMService() { diff --git a/src/radio/spotifysearchplaylisttype.cpp b/src/radio/spotifysearchplaylisttype.cpp new file mode 100644 index 000000000..97cc675e5 --- /dev/null +++ b/src/radio/spotifysearchplaylisttype.cpp @@ -0,0 +1,50 @@ +/* This file is part of Clementine. + Copyright 2010, David Sansome + + Clementine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Clementine is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Clementine. If not, see . +*/ + +#include "spotifysearchplaylisttype.h" +#include "spotifyservice.h" + +const char* SpotifySearchPlaylistType::kName = "spotify-search"; + +SpotifySearchPlaylistType::SpotifySearchPlaylistType(SpotifyService* service) + : service_(service) { +} + +QIcon SpotifySearchPlaylistType::icon(Playlist* playlist) const { + return QIcon(":icons/svg/spotify.svg"); +} + +QString SpotifySearchPlaylistType::search_hint_text(Playlist* playlist) const { + return QObject::tr("Search Spotify"); +} + +QString SpotifySearchPlaylistType::empty_playlist_text(Playlist* playlist) const { + return QObject::tr("Start typing in the search box above to find music on Spotify"); +} + +QString SpotifySearchPlaylistType::playlist_view_css(Playlist* playlist) const { + // TODO + return QString(); +} + +bool SpotifySearchPlaylistType::has_special_search_behaviour(Playlist* playlist) const { + return true; +} + +void SpotifySearchPlaylistType::Search(const QString& text, Playlist* playlist) { + service_->Search(text, playlist); +} diff --git a/src/radio/spotifysearchplaylisttype.h b/src/radio/spotifysearchplaylisttype.h new file mode 100644 index 000000000..6dae48b46 --- /dev/null +++ b/src/radio/spotifysearchplaylisttype.h @@ -0,0 +1,44 @@ +/* This file is part of Clementine. + Copyright 2010, David Sansome + + Clementine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Clementine is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Clementine. If not, see . +*/ + +#ifndef SPOTIFYSEARCHPLAYLISTTYPE_H +#define SPOTIFYSEARCHPLAYLISTTYPE_H + +#include "playlist/specialplaylisttype.h" + +class SpotifyService; + +class SpotifySearchPlaylistType : public SpecialPlaylistType { +public: + SpotifySearchPlaylistType(SpotifyService* service); + + static const char* kName; + virtual QString name() const { return kName; } + + virtual QIcon icon(Playlist* playlist) const; + virtual QString search_hint_text(Playlist* playlist) const; + virtual QString empty_playlist_text(Playlist* playlist) const; + virtual QString playlist_view_css(Playlist* playlist) const; + + virtual bool has_special_search_behaviour(Playlist* playlist) const; + virtual void Search(const QString& text, Playlist* playlist); + +private: + SpotifyService* service_; +}; + +#endif // SPOTIFYSEARCHPLAYLISTTYPE_H diff --git a/src/radio/spotifyservice.cpp b/src/radio/spotifyservice.cpp index 4835b6930..ddda4bb47 100644 --- a/src/radio/spotifyservice.cpp +++ b/src/radio/spotifyservice.cpp @@ -1,16 +1,14 @@ #include "radiomodel.h" #include "spotifyserver.h" #include "spotifyservice.h" +#include "spotifysearchplaylisttype.h" #include "spotifyurlhandler.h" #include "core/database.h" #include "core/logging.h" -#include "core/mergedproxymodel.h" #include "core/player.h" #include "core/taskmanager.h" -#include "library/library.h" -#include "library/librarybackend.h" -#include "library/libraryfilterwidget.h" -#include "library/librarymodel.h" +#include "playlist/playlist.h" +#include "playlist/playlistmanager.h" #include "spotifyblob/spotifymessagehandler.h" #include "ui/iconloader.h" @@ -18,12 +16,10 @@ #include #include #include -#include const char* SpotifyService::kServiceName = "Spotify"; const char* SpotifyService::kSettingsGroup = "Spotify"; -const char* SpotifyService::kSearchSongsTable = "spotify_search_songs"; -const char* SpotifyService::kSearchFtsTable = "spotify_search_songs_fts"; +const int SpotifyService::kSearchDelayMsec = 400; SpotifyService::SpotifyService(RadioModel* parent) : RadioService(kServiceName, parent), @@ -31,13 +27,12 @@ SpotifyService::SpotifyService(RadioModel* parent) url_handler_(new SpotifyUrlHandler(this, this)), blob_process_(NULL), root_(NULL), - search_results_(NULL), starred_(NULL), inbox_(NULL), login_task_id_(0), + pending_search_playlist_(NULL), context_menu_(NULL), - library_filter_(NULL), - library_sort_model_(new QSortFilterProxyModel(this)) { + search_delay_(new QTimer(this)) { #ifdef Q_OS_DARWIN blob_path_ = QCoreApplication::applicationDirPath() + "/../Resources/clementine-spotifyblob"; #else @@ -45,18 +40,13 @@ SpotifyService::SpotifyService(RadioModel* parent) #endif qLog(Debug) << "Loading spotify blob from:" << blob_path_; - // Create the library backend in the database thread - library_backend_ = new LibraryBackend; - library_backend_->Init(parent->db_thread()->Worker(), - kSearchSongsTable, QString(), QString(), kSearchFtsTable); - library_model_ = new LibraryModel(library_backend_, parent->task_manager(), this); + model()->player()->RegisterUrlHandler(url_handler_); + model()->player()->playlists()->RegisterSpecialPlaylistType( + new SpotifySearchPlaylistType(this)); - library_sort_model_->setSourceModel(library_model_); - library_sort_model_->setSortRole(LibraryModel::Role_SortText); - library_sort_model_->setDynamicSortFilter(true); - library_sort_model_->sort(0); - - model()->player()->AddUrlHandler(url_handler_); + search_delay_->setInterval(kSearchDelayMsec); + search_delay_->setSingleShot(true); + connect(search_delay_, SIGNAL(timeout()), SLOT(DoSearch())); } SpotifyService::~SpotifyService() { @@ -75,8 +65,6 @@ void SpotifyService::LazyPopulate(QStandardItem* item) { break; case Type_SearchResults: - library_model_->Init(); - model()->merged_model()->AddSubModel(item->index(), library_sort_model_); break; case Type_InboxPlaylist: @@ -181,9 +169,9 @@ void SpotifyService::PlaylistsUpdated(const protobuf::Playlists& response) { // Create starred and inbox playlists if they're not here already if (!search_results_) { - search_results_ = new QStandardItem(tr("Search results")); + search_results_ = new QStandardItem(IconLoader::Load("edit-find"), + tr("Search Spotify (opens a new tab)")); search_results_->setData(Type_SearchResults, RadioModel::Role_Type); - search_results_->setData(true, RadioModel::Role_CanLazyLoad); starred_ = new QStandardItem(QIcon(":/star-on.png"), tr("Starred")); starred_->setData(Type_StarredPlaylist, RadioModel::Role_Type); @@ -325,30 +313,22 @@ void SpotifyService::EnsureMenuCreated() { context_menu_->addActions(GetPlaylistActions()); context_menu_->addSeparator(); - QAction* config_action = context_menu_->addAction(IconLoader::Load("configure"), tr("Configure Spotify..."), this, SLOT(ShowConfig())); - - library_filter_ = new LibraryFilterWidget(0); - library_filter_->SetSettingsGroup(kSettingsGroup); - library_filter_->SetLibraryModel(library_model_); - library_filter_->SetFilterHint(tr("Search Spotify")); - library_filter_->SetAgeFilterEnabled(false); - library_filter_->SetGroupByEnabled(false); - library_filter_->AddMenuAction(config_action); - library_filter_->SetApplyFilterToLibrary(false); - library_filter_->SetDelayBehaviour(LibraryFilterWidget::AlwaysDelayed); - - connect(library_filter_, SIGNAL(Filter(QString)), SLOT(Search(QString))); + context_menu_->addAction(IconLoader::Load("edit-find"), tr("Search Spotify (opens a new tab)..."), this, SLOT(OpenSearchTab())); + context_menu_->addSeparator(); + context_menu_->addAction(IconLoader::Load("configure"), tr("Configure Spotify..."), this, SLOT(ShowConfig())); } -QWidget* SpotifyService::HeaderWidget() const { - const_cast(this)->EnsureMenuCreated(); - return library_filter_; +void SpotifyService::Search(const QString& text, Playlist* playlist) { + EnsureServerCreated(); + + pending_search_ = text; + pending_search_playlist_ = playlist; + search_delay_->start(); } -void SpotifyService::Search(const QString& text) { - if (!text.isEmpty()) { - pending_search_ = text; - server_->Search(text, 250); +void SpotifyService::DoSearch() { + if (!pending_search_.isEmpty()) { + server_->Search(pending_search_, 200); } } @@ -370,11 +350,21 @@ void SpotifyService::SearchResults(const protobuf::SearchResponse& response) { qLog(Debug) << "Got" << songs.count() << "results"; - library_backend_->DeleteAll(); - library_backend_->AddOrUpdateSongs(songs); + pending_search_playlist_->Clear(); + pending_search_playlist_->InsertSongs(songs); } SpotifyServer* SpotifyService::server() const { const_cast(this)->EnsureServerCreated(); return server_; } + +void SpotifyService::ShowContextMenu(const QModelIndex& index, const QPoint& global_pos) { + EnsureMenuCreated(); + context_menu_->popup(global_pos); +} + +void SpotifyService::OpenSearchTab() { + model()->player()->playlists()->New(tr("Search Spotify"), SongList(), + SpotifySearchPlaylistType::kName); +} diff --git a/src/radio/spotifyservice.h b/src/radio/spotifyservice.h index b4f233488..1712742a4 100644 --- a/src/radio/spotifyservice.h +++ b/src/radio/spotifyservice.h @@ -10,14 +10,11 @@ #include -class LibraryBackend; -class LibraryModel; +class Playlist; class SpotifyServer; class SpotifyUrlHandler; class QMenu; -class QSortFilterProxyModel; -class QTemporaryFile; class SpotifyService : public RadioService { Q_OBJECT @@ -40,17 +37,15 @@ public: static const char* kServiceName; static const char* kSettingsGroup; - static const char* kSearchSongsTable; - static const char* kSearchFtsTable; - - virtual QStandardItem* CreateRootItem(); - virtual void LazyPopulate(QStandardItem* parent); - - void Login(const QString& username, const QString& password); + static const int kSearchDelayMsec; + QStandardItem* CreateRootItem(); + void LazyPopulate(QStandardItem* parent); + void ShowContextMenu(const QModelIndex& index, const QPoint& global_pos); PlaylistItem::Options playlistitem_options() const; - QWidget* HeaderWidget() const; + void Login(const QString& username, const QString& password); + void Search(const QString& text, Playlist* playlist); SpotifyServer* server() const; @@ -79,7 +74,8 @@ private slots: void UserPlaylistLoaded(const protobuf::LoadPlaylistResponse& response); void SearchResults(const protobuf::SearchResponse& response); - void Search(const QString& text); + void OpenSearchTab(); + void DoSearch(); private: SpotifyServer* server_; @@ -96,16 +92,12 @@ private: int login_task_id_; QString pending_search_; + Playlist* pending_search_playlist_; QMenu* context_menu_; QModelIndex context_item_; - QTemporaryFile* database_file_; - boost::shared_ptr database_; - LibraryBackend* library_backend_; - LibraryFilterWidget* library_filter_; - LibraryModel* library_model_; - QSortFilterProxyModel* library_sort_model_; + QTimer* search_delay_; }; #endif diff --git a/src/scripting/python/player.sip b/src/scripting/python/player.sip index aa5136601..2e9b3931b 100644 --- a/src/scripting/python/player.sip +++ b/src/scripting/python/player.sip @@ -12,8 +12,8 @@ public: PlaylistItemPtr GetItemAt(int pos) const; PlaylistManagerInterface* playlists() const; - void AddUrlHandler(UrlHandler* handler); - void RemoveUrlHandler(UrlHandler* handler); + void RegisterUrlHandler(UrlHandler* handler); + void UnregisterUrlHandler(UrlHandler* handler); public slots: // Manual track change to the specified track diff --git a/src/smartplaylists/searchpreview.cpp b/src/smartplaylists/searchpreview.cpp index adc92194d..d638cb00e 100644 --- a/src/smartplaylists/searchpreview.cpp +++ b/src/smartplaylists/searchpreview.cpp @@ -52,7 +52,7 @@ SearchPreview::~SearchPreview() { void SearchPreview::set_library(LibraryBackend* backend) { backend_ = backend; - model_ = new Playlist(NULL, NULL, backend_, -1, this); + model_ = new Playlist(NULL, NULL, backend_, -1, QString(), this); ui_->tree->setModel(model_); ui_->tree->SetPlaylist(model_); ui_->tree->SetItemDelegates(backend_);