diff --git a/src/core/player.h b/src/core/player.h index 946e3896c..09b82d52f 100644 --- a/src/core/player.h +++ b/src/core/player.h @@ -65,7 +65,7 @@ class Player : public QObject { Engine::State GetState() const; int GetVolume() const; - boost::shared_ptr GetCurrentItem() const { return current_item_; } + PlaylistItemPtr GetCurrentItem() const { return current_item_; } // MPRIS enum DBusCaps { @@ -175,7 +175,7 @@ class Player : public QObject { LastFMService* lastfm_; QSettings settings_; - boost::shared_ptr current_item_; + PlaylistItemPtr current_item_; boost::scoped_ptr engine_; Engine::TrackChangeType stream_change_type_; diff --git a/src/playlist/playlist.cpp b/src/playlist/playlist.cpp index 80448cf7c..37f9a136e 100644 --- a/src/playlist/playlist.cpp +++ b/src/playlist/playlist.cpp @@ -673,7 +673,7 @@ QModelIndex Playlist::InsertItemsWithoutUndo(const PlaylistItemList& items, beginInsertRows(QModelIndex(), start, end); for (int i=start ; i<=end ; ++i) { - boost::shared_ptr item = items[i - start]; + PlaylistItemPtr item = items[i - start]; items_.insert(i, item); virtual_items_ << virtual_items_.count(); @@ -948,7 +948,7 @@ PlaylistItemList Playlist::RemoveItemsWithoutUndo(int row, int count) { // Remove items PlaylistItemList ret; for (int i=0 ; i item(items_.takeAt(row)); + PlaylistItemPtr item(items_.takeAt(row)); ret << item; if (item->type() == "Library") { @@ -1118,7 +1118,7 @@ QSortFilterProxyModel* Playlist::proxy() const { SongList Playlist::GetAllSongs() const { SongList ret; - foreach (boost::shared_ptr item, items_) { + foreach (PlaylistItemPtr item, items_) { ret << item->Metadata(); } return ret; @@ -1126,7 +1126,7 @@ SongList Playlist::GetAllSongs() const { quint64 Playlist::GetTotalLength() const { quint64 ret = 0; - foreach (boost::shared_ptr item, items_) { + foreach (PlaylistItemPtr item, items_) { int length = item->Metadata().length(); if (length > 0) ret += length; diff --git a/src/playlist/playlist.h b/src/playlist/playlist.h index 6c7aa4e86..14cc13b28 100644 --- a/src/playlist/playlist.h +++ b/src/playlist/playlist.h @@ -94,8 +94,7 @@ class Playlist : public QAbstractListModel { static const char* kPlayNowMimetype; static bool CompareItems(int column, Qt::SortOrder order, - boost::shared_ptr a, - boost::shared_ptr b); + PlaylistItemPtr a, PlaylistItemPtr b); static QString column_name(Column column); static bool column_is_editable(Playlist::Column column); @@ -116,8 +115,8 @@ class Playlist : public QAbstractListModel { int previous_index() const; bool stop_after_current() const; - const boost::shared_ptr& item_at(int index) const { return items_[index]; } - boost::shared_ptr current_item() const { return current_item_; } + const PlaylistItemPtr& item_at(int index) const { return items_[index]; } + PlaylistItemPtr current_item() const { return current_item_; } PlaylistItem::Options current_item_options() const; Song current_item_metadata() const; @@ -226,7 +225,7 @@ class Playlist : public QAbstractListModel { // that they will be played. // A map of library ID to playlist item - for fast lookups when library // items change. - QMultiMap > library_items_by_id_; + QMultiMap library_items_by_id_; QPersistentModelIndex current_item_index_; QPersistentModelIndex last_played_item_index_; @@ -234,7 +233,7 @@ class Playlist : public QAbstractListModel { bool current_is_paused_; int current_virtual_index_; - boost::shared_ptr current_item_; + PlaylistItemPtr current_item_; bool is_shuffled_; diff --git a/src/playlist/playlistbackend.h b/src/playlist/playlistbackend.h index 9200b9aa6..a5b33c267 100644 --- a/src/playlist/playlistbackend.h +++ b/src/playlist/playlistbackend.h @@ -40,7 +40,7 @@ class PlaylistBackend : public QObject { int last_played; }; typedef QList PlaylistList; - typedef QFuture > PlaylistItemFuture; + typedef QFuture PlaylistItemFuture; PlaylistList GetAllPlaylists(); Playlist GetPlaylist(int id); @@ -57,7 +57,7 @@ class PlaylistBackend : public QObject { void SavePlaylist(int playlist, const PlaylistItemList& items, int last_played); private: - static boost::shared_ptr NewSongFromQuery(const SqlRow& row); + static PlaylistItemPtr NewSongFromQuery(const SqlRow& row); boost::shared_ptr db_; }; diff --git a/src/playlist/playlistitem.cpp b/src/playlist/playlistitem.cpp index 4a2ab79d9..4810007c3 100644 --- a/src/playlist/playlistitem.cpp +++ b/src/playlist/playlistitem.cpp @@ -63,7 +63,7 @@ void PlaylistItem::ClearTemporaryMetadata() { temp_metadata_ = Song(); } -static void ReloadPlaylistItem(boost::shared_ptr item) { +static void ReloadPlaylistItem(PlaylistItemPtr item) { item->Reload(); } diff --git a/src/playlist/playlistitem.h b/src/playlist/playlistitem.h index 6b2db7b3b..c4105d0d4 100644 --- a/src/playlist/playlistitem.h +++ b/src/playlist/playlistitem.h @@ -128,7 +128,8 @@ class PlaylistItem : public boost::enable_shared_from_this { Song temp_metadata_; }; -typedef QList > PlaylistItemList; +typedef boost::shared_ptr PlaylistItemPtr; +typedef QList PlaylistItemList; Q_DECLARE_OPERATORS_FOR_FLAGS(PlaylistItem::Options); diff --git a/src/playlist/playlistmanager.cpp b/src/playlist/playlistmanager.cpp index 578a758b5..9373496ef 100644 --- a/src/playlist/playlistmanager.cpp +++ b/src/playlist/playlistmanager.cpp @@ -263,7 +263,7 @@ void PlaylistManager::SongsDiscovered(const SongList& songs) { foreach (const Song& song, songs) { foreach (const Data& data, playlists_) { PlaylistItemList items = data.p->library_items_by_id(song.id()); - foreach (boost::shared_ptr item, items) { + foreach (PlaylistItemPtr item, items) { if (item->Metadata().directory_id() != song.directory_id()) continue; static_cast(item.get())->SetMetadata(song); diff --git a/src/radio/lastfmservice.cpp b/src/radio/lastfmservice.cpp index f00583d03..2857850de 100644 --- a/src/radio/lastfmservice.cpp +++ b/src/radio/lastfmservice.cpp @@ -18,6 +18,7 @@ #include "radioitem.h" #include "lastfmstationdialog.h" #include "radiomodel.h" +#include "radioplaylistitem.h" #include "core/networkaccessmanager.h" #include "core/song.h" #include "core/taskmanager.h" @@ -725,3 +726,25 @@ PlaylistItem::Options LastFMService::playlistitem_options() const { PlaylistItem::PauseDisabled | PlaylistItem::ContainsMultipleTracks; } + +PlaylistItemPtr LastFMService::PlaylistItemForUrl(const QUrl& url) { + // This is a bit of a hack, it's only used by the artist/song info tag + // widgets for tag radio and similar artists radio. + + PlaylistItemPtr ret; + + if (url.scheme() != "lastfm") + return ret; + + QStringList sections(url.path().split("/", QString::SkipEmptyParts)); + + if (sections.count() == 2 && url.host() == "artist" && sections[1] == "similarartists") { + ret.reset(new RadioPlaylistItem(this, url, + tr("Last.fm Similar Artists to %1").arg(sections[0]), QString())); + } else if (sections.count() == 1 && url.host() == "globaltags") { + ret.reset(new RadioPlaylistItem(this, url, + tr("Last.fm Tag Radio: %1").arg(sections[0]), QString())); + } + + return ret; +} diff --git a/src/radio/lastfmservice.h b/src/radio/lastfmservice.h index 5ee8e330b..1ed867092 100644 --- a/src/radio/lastfmservice.h +++ b/src/radio/lastfmservice.h @@ -32,6 +32,7 @@ uint qHash(const lastfm::Track& track); #include "radioservice.h" #include "lastfmstationdialog.h" #include "core/song.h" +#include "playlist/playlistitem.h" #include #include @@ -104,11 +105,14 @@ class LastFMService : public RadioService { void FetchMoreTracks(); + PlaylistItemPtr PlaylistItemForUrl(const QUrl& url); + public slots: void NowPlaying(const Song& song); void Scrobble(); void Love(); void Ban(); + void ShowConfig(); signals: void AuthenticationComplete(bool success); @@ -119,7 +123,6 @@ class LastFMService : public RadioService { void AuthenticateReplyFinished(); void RefreshFriendsFinished(); void RefreshNeighboursFinished(); - void ShowConfig(); void TunerTrackAvailable(); void TunerError(lastfm::ws::Error error); diff --git a/src/songinfo/songinfobase.cpp b/src/songinfo/songinfobase.cpp index 827da9dae..b5f7578cc 100644 --- a/src/songinfo/songinfobase.cpp +++ b/src/songinfo/songinfobase.cpp @@ -212,4 +212,8 @@ void SongInfoBase::ConnectWidget(QWidget* widget) { if (widget->metaObject()->indexOfSignal("ShowSettingsDialog()") != -1) { connect(widget, SIGNAL(ShowSettingsDialog()), SIGNAL(ShowSettingsDialog())); } + + if (widget->metaObject()->indexOfSignal("AddPlaylistItems(PlaylistItemList)") != -1) { + connect(widget, SIGNAL(AddPlaylistItems(PlaylistItemList)), SIGNAL(AddPlaylistItems(PlaylistItemList))); + } } diff --git a/src/songinfo/songinfobase.h b/src/songinfo/songinfobase.h index 3e3a269a0..bdd128b90 100644 --- a/src/songinfo/songinfobase.h +++ b/src/songinfo/songinfobase.h @@ -22,6 +22,7 @@ #include "collapsibleinfopane.h" #include "songinfofetcher.h" #include "core/song.h" +#include "playlist/playlistitem.h" #include "widgets/widgetfadehelper.h" class CollapsibleInfoPane; @@ -46,6 +47,7 @@ public slots: signals: void ShowSettingsDialog(); + void AddPlaylistItems(const PlaylistItemList& items); protected: void showEvent(QShowEvent* e); diff --git a/src/songinfo/tagwidget.cpp b/src/songinfo/tagwidget.cpp index b30d3a22a..bdca97657 100644 --- a/src/songinfo/tagwidget.cpp +++ b/src/songinfo/tagwidget.cpp @@ -15,6 +15,8 @@ */ #include "tagwidget.h" +#include "radio/lastfmservice.h" +#include "radio/radiomodel.h" #include "ui/flowlayout.h" #include @@ -93,6 +95,10 @@ void TagWidgetTag::paintEvent(QPaintEvent*) { p.drawText(text_rect, text_); } +void TagWidgetTag::mouseReleaseEvent(QMouseEvent*) { + emit Clicked(); +} + TagWidget::TagWidget(QWidget* parent) : QWidget(parent) @@ -105,6 +111,27 @@ void TagWidget::AddTag(const QString& tag) { return; TagWidgetTag* widget = new TagWidgetTag(icon_, tag, this); + connect(widget, SIGNAL(Clicked()), SLOT(TagClicked())); + layout()->addWidget(widget); tags_ << widget; } + +void TagWidget::TagClicked() { + TagWidgetTag* tag = qobject_cast(sender()); + if (!tag) + return; + + LastFMService* last_fm = RadioModel::Service(); + if (!last_fm->IsAuthenticated()) { + last_fm->ShowConfig(); + return; + } + + QUrl url(url_pattern_.arg(tag->text())); + PlaylistItemPtr item(last_fm->PlaylistItemForUrl(url)); + if (!item) + return; + + emit AddPlaylistItems(PlaylistItemList() << item); +} diff --git a/src/songinfo/tagwidget.h b/src/songinfo/tagwidget.h index 4e17afc42..0b7770a73 100644 --- a/src/songinfo/tagwidget.h +++ b/src/songinfo/tagwidget.h @@ -17,6 +17,8 @@ #ifndef TAGWIDGET_H #define TAGWIDGET_H +#include "playlist/playlistitem.h" + #include #include @@ -40,11 +42,16 @@ public: void set_background_opacity(float opacity); QSize sizeHint() const; + QString text() const { return text_; } + +signals: + void Clicked(); protected: void enterEvent(QEvent*); void leaveEvent(QEvent*); void paintEvent(QPaintEvent*); + void mouseReleaseEvent(QMouseEvent*); private: QString text_; @@ -66,6 +73,12 @@ public: int count() const { return tags_.count(); } +signals: + void AddPlaylistItems(const PlaylistItemList& items); + +private slots: + void TagClicked(); + private: QString url_pattern_; QIcon icon_; diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index f51af9d9e..be9bc92e4 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -1596,6 +1596,7 @@ void MainWindow::ConnectInfoView(SongInfoBase* view) { connect(player_, SIGNAL(Stopped()), view, SLOT(SongFinished())); connect(view, SIGNAL(ShowSettingsDialog()), SLOT(ShowSongInfoConfig())); + connect(view, SIGNAL(AddPlaylistItems(PlaylistItemList)), SLOT(InsertRadioItems(PlaylistItemList))); } void MainWindow::ShowSongInfoConfig() { diff --git a/tests/playlist_test.cpp b/tests/playlist_test.cpp index 5ff50ea6b..ce9714904 100644 --- a/tests/playlist_test.cpp +++ b/tests/playlist_test.cpp @@ -440,7 +440,7 @@ TEST_F(PlaylistTest, LibraryIdMapSingle) { song.Init("title", "artist", "album", 123); song.set_id(1); - boost::shared_ptr item(new LibraryPlaylistItem(song)); + PlaylistItemPtr item(new LibraryPlaylistItem(song)); playlist_.InsertItems(PlaylistItemList() << item); EXPECT_EQ(0, playlist_.library_items_by_id(-1).count()); @@ -459,7 +459,7 @@ TEST_F(PlaylistTest, LibraryIdMapInvalid) { invalid.Init("title", "artist", "album", 123); ASSERT_EQ(-1, invalid.id()); - boost::shared_ptr item(new LibraryPlaylistItem(invalid)); + PlaylistItemPtr item(new LibraryPlaylistItem(invalid)); playlist_.InsertItems(PlaylistItemList() << item); EXPECT_EQ(0, playlist_.library_items_by_id(-1).count()); @@ -477,9 +477,9 @@ TEST_F(PlaylistTest, LibraryIdMapMulti) { two.Init("title 2", "artist 2", "album 2", 123); two.set_id(2); - boost::shared_ptr item_one(new LibraryPlaylistItem(one)); - boost::shared_ptr item_two(new LibraryPlaylistItem(two)); - boost::shared_ptr item_three(new LibraryPlaylistItem(one)); + PlaylistItemPtr item_one(new LibraryPlaylistItem(one)); + PlaylistItemPtr item_two(new LibraryPlaylistItem(two)); + PlaylistItemPtr item_three(new LibraryPlaylistItem(one)); playlist_.InsertItems(PlaylistItemList() << item_one << item_two << item_three); EXPECT_EQ(2, playlist_.library_items_by_id(1).count());