Double-click on radio items to play

This commit is contained in:
David Sansome 2009-12-29 23:17:54 +00:00
parent 939e4b5264
commit 92db175819
12 changed files with 70 additions and 59 deletions

1
TODO
View File

@ -10,7 +10,6 @@
Last.fm: Last.fm:
- Artist/tag/etc. radio - Artist/tag/etc. radio
- Double click from radio list
- More types of radio - More types of radio
Long-term: Long-term:

View File

@ -145,34 +145,33 @@ void LastFMService::AuthenticateReplyFinished() {
emit AuthenticationComplete(true); emit AuthenticationComplete(true);
} }
QList<RadioItem::PlaylistData> LastFMService::DataForItem(RadioItem* item) { QUrl LastFMService::UrlForItem(const RadioItem* item) const {
QList<RadioItem::PlaylistData> ret; switch (item->type) {
case Type_MyRecommendations:
return "lastfm://user/" + lastfm::ws::Username + "/recommended";
case Type_MyLoved:
return "lastfm://user/" + lastfm::ws::Username + "/loved";
case Type_MyNeighbourhood:
return "lastfm://user/" + lastfm::ws::Username + "/neighbours";
case Type_MyRadio:
return "lastfm://user/" + lastfm::ws::Username + "/library";
}
return QUrl();
}
QString LastFMService::TitleForItem(const RadioItem* item) const {
const QString user(lastfm::ws::Username); const QString user(lastfm::ws::Username);
switch (item->type) { switch (item->type) {
case Type_MyRecommendations: case Type_MyRecommendations: return user + "'s Recommended Radio";
ret << RadioItem::PlaylistData(user + "'s Recommended Radio", case Type_MyLoved: return user + "'s Loved Tracks";
"lastfm://user/" + lastfm::ws::Username + "/recommended"); case Type_MyNeighbourhood: return user + "'s Neighbour Radio";
break; case Type_MyRadio: return user + "'s Library";
case Type_MyLoved:
ret << RadioItem::PlaylistData(user + "'s Loved Tracks",
"lastfm://user/" + lastfm::ws::Username + "/loved");
break;
case Type_MyNeighbourhood:
ret << RadioItem::PlaylistData(user + "'s Neighbour Radio",
"lastfm://user/" + lastfm::ws::Username + "/neighbours");
break;
case Type_MyRadio:
ret << RadioItem::PlaylistData(user + "'s Library",
"lastfm://user/" + lastfm::ws::Username + "/library");
break;
} }
return QString();
return ret;
} }
void LastFMService::StartLoading(const QUrl& url) { void LastFMService::StartLoading(const QUrl& url) {

View File

@ -33,13 +33,19 @@ class LastFMService : public RadioService {
// RadioService // RadioService
RadioItem* CreateRootItem(RadioItem* parent); RadioItem* CreateRootItem(RadioItem* parent);
void LazyPopulate(RadioItem *item); void LazyPopulate(RadioItem *item);
QList<RadioItem::PlaylistData> DataForItem(RadioItem* item);
QUrl UrlForItem(const RadioItem* item) const;
QString TitleForItem(const RadioItem* item) const;
void ShowContextMenu(RadioItem *item, const QPoint &global_pos); void ShowContextMenu(RadioItem *item, const QPoint &global_pos);
void StartLoading(const QUrl& url); void StartLoading(const QUrl& url);
void LoadNext(const QUrl& url); void LoadNext(const QUrl& url);
bool IsPauseAllowed() const { return false; } bool IsPauseAllowed() const { return false; }
bool ShowLastFmControls() const { return true; } bool ShowLastFmControls() const { return true; }
// Last.fm specific stuff
bool IsAuthenticated() const; bool IsAuthenticated() const;
bool IsScrobblingEnabled() const { return scrobbling_enabled_; } bool IsScrobblingEnabled() const { return scrobbling_enabled_; }
void Authenticate(const QString& username, const QString& password); void Authenticate(const QString& username, const QString& password);

View File

@ -157,6 +157,7 @@ MainWindow::MainWindow(QWidget *parent)
connect(radio_model_, SIGNAL(StreamReady(QUrl,QUrl)), player_, SLOT(StreamReady(QUrl,QUrl))); connect(radio_model_, SIGNAL(StreamReady(QUrl,QUrl)), player_, SLOT(StreamReady(QUrl,QUrl)));
connect(radio_model_, SIGNAL(StreamMetadataFound(QUrl,Song)), playlist_, SLOT(SetStreamMetadata(QUrl,Song))); connect(radio_model_, SIGNAL(StreamMetadataFound(QUrl,Song)), playlist_, SLOT(SetStreamMetadata(QUrl,Song)));
connect(radio_model_->GetLastFMService(), SIGNAL(ScrobblingEnabledChanged(bool)), SLOT(ScrobblingEnabledChanged(bool))); connect(radio_model_->GetLastFMService(), SIGNAL(ScrobblingEnabledChanged(bool)), SLOT(ScrobblingEnabledChanged(bool)));
connect(ui_.radio_view, SIGNAL(doubleClicked(QModelIndex)), SLOT(RadioDoubleClick(QModelIndex)));
// Tray icon // Tray icon
QMenu* tray_menu = new QMenu(this); QMenu* tray_menu = new QMenu(this);
@ -360,3 +361,11 @@ void MainWindow::Love() {
radio_model_->GetLastFMService()->Love(); radio_model_->GetLastFMService()->Love();
ui_.action_love->setEnabled(false); ui_.action_love->setEnabled(false);
} }
void MainWindow::RadioDoubleClick(const QModelIndex& index) {
QModelIndex first_song = playlist_->InsertRadioStations(
QList<RadioItem*>() << radio_model_->IndexToItem(index));
if (first_song.isValid() && player_->GetState() != Engine::Playing)
player_->PlayAt(first_song.row());
}

View File

@ -49,6 +49,7 @@ class MainWindow : public QMainWindow {
void UpdateTrackPosition(); void UpdateTrackPosition();
void RadioDoubleClick(const QModelIndex& index);
void ScrobblingEnabledChanged(bool value); void ScrobblingEnabledChanged(bool value);
void Love(); void Love();

View File

@ -133,7 +133,7 @@ bool Playlist::dropMimeData(const QMimeData* data, Qt::DropAction action, int ro
InsertSongs(song_data->songs, row); InsertSongs(song_data->songs, row);
} else if (const RadioMimeData* radio_data = qobject_cast<const RadioMimeData*>(data)) { } else if (const RadioMimeData* radio_data = qobject_cast<const RadioMimeData*>(data)) {
// Dragged from the Radio pane // Dragged from the Radio pane
InsertRadioStations(radio_data->services, radio_data->urls(), radio_data->titles, row); InsertRadioStations(radio_data->items, row);
} else if (data->hasFormat(kRowsMimetype)) { } else if (data->hasFormat(kRowsMimetype)) {
// Dragged from the playlist // Dragged from the playlist
// Rearranging it is tricky... // Rearranging it is tricky...
@ -245,17 +245,15 @@ QModelIndex Playlist::InsertSongs(const SongList& songs, int after) {
return InsertItems(items, after); return InsertItems(items, after);
} }
QModelIndex Playlist::InsertRadioStations(const QList<RadioService*>& services, QModelIndex Playlist::InsertRadioStations(const QList<RadioItem*>& items, int after) {
const QList<QUrl>& urls, QList<PlaylistItem*> playlist_items;
const QStringList& titles, int after) { foreach (RadioItem* item, items) {
Q_ASSERT(services.count() == urls.count()); if (!item->playable)
Q_ASSERT(services.count() == titles.count()); continue;
QList<PlaylistItem*> items; playlist_items << new RadioPlaylistItem(item->service, item->Url(), item->Title());
for (int i=0 ; i<services.count() ; ++i) {
items << new RadioPlaylistItem(services[i], urls[i], titles[i]);
} }
return InsertItems(items, after); return InsertItems(playlist_items, after);
} }
QMimeData* Playlist::mimeData(const QModelIndexList& indexes) const { QMimeData* Playlist::mimeData(const QModelIndexList& indexes) const {

View File

@ -6,6 +6,7 @@
#include "playlistitem.h" #include "playlistitem.h"
#include "song.h" #include "song.h"
#include "radioitem.h"
class RadioService; class RadioService;
@ -62,9 +63,7 @@ class Playlist : public QAbstractListModel {
// Changing the playlist // Changing the playlist
QModelIndex InsertItems(const QList<PlaylistItem*>& items, int after = -1); QModelIndex InsertItems(const QList<PlaylistItem*>& items, int after = -1);
QModelIndex InsertSongs(const SongList& items, int after = -1); QModelIndex InsertSongs(const SongList& items, int after = -1);
QModelIndex InsertRadioStations(const QList<RadioService*>& services, QModelIndex InsertRadioStations(const QList<RadioItem*>& items, int after = -1);
const QList<QUrl>& urls,
const QStringList& titles, int after = -1);
QModelIndex InsertPaths(QList<QUrl> urls, int after = -1); QModelIndex InsertPaths(QList<QUrl> urls, int after = -1);
void StopAfter(int row); void StopAfter(int row);

View File

@ -1,4 +1,5 @@
#include "radioitem.h" #include "radioitem.h"
#include "radioservice.h"
RadioItem::RadioItem(RadioService* _service, int type, const QString& key, RadioItem::RadioItem(RadioService* _service, int type, const QString& key,
RadioItem* parent) RadioItem* parent)
@ -7,3 +8,11 @@ RadioItem::RadioItem(RadioService* _service, int type, const QString& key,
playable(false) playable(false)
{ {
} }
QUrl RadioItem::Url() const {
return service->UrlForItem(this);
}
QString RadioItem::Title() const {
return service->TitleForItem(this);
}

View File

@ -15,16 +15,12 @@ class RadioItem : public SimpleTreeItem<RadioItem> {
Type_Service, Type_Service,
}; };
struct PlaylistData {
PlaylistData(const QString& _title, const QUrl& _url) : title(_title), url(_url) {}
QString title;
QUrl url;
};
RadioItem(RadioService* _service, int type, const QString& key = QString::null, RadioItem(RadioService* _service, int type, const QString& key = QString::null,
RadioItem* parent = NULL); RadioItem* parent = NULL);
QUrl Url() const;
QString Title() const;
QIcon icon; QIcon icon;
RadioService* service; RadioService* service;
bool playable; bool playable;

View File

@ -3,14 +3,13 @@
#include <QMimeData> #include <QMimeData>
class RadioService; class RadioItem;
class RadioMimeData : public QMimeData { class RadioMimeData : public QMimeData {
Q_OBJECT Q_OBJECT
public: public:
QList<RadioService*> services; QList<RadioItem*> items;
QList<QString> titles;
}; };
#endif // RADIOMIMEDATA_H #endif // RADIOMIMEDATA_H

View File

@ -85,20 +85,15 @@ QStringList RadioModel::mimeTypes() const {
QMimeData* RadioModel::mimeData(const QModelIndexList& indexes) const { QMimeData* RadioModel::mimeData(const QModelIndexList& indexes) const {
QList<QUrl> urls; QList<QUrl> urls;
QList<RadioService*> services; QList<RadioItem*> items;
QStringList titles;
foreach (const QModelIndex& index, indexes) { foreach (const QModelIndex& index, indexes) {
RadioItem* item = IndexToItem(index); RadioItem* item = IndexToItem(index);
if (!item || !item->service || !item->playable) if (!item || !item->service || !item->playable)
continue; continue;
QList<RadioItem::PlaylistData> item_data(item->service->DataForItem(item)); items << item;
foreach (const RadioItem::PlaylistData& data, item_data) { urls << item->service->UrlForItem(item);
urls << data.url;
services << item->service;
titles << data.title;
}
} }
if (urls.isEmpty()) if (urls.isEmpty())
@ -106,8 +101,7 @@ QMimeData* RadioModel::mimeData(const QModelIndexList& indexes) const {
RadioMimeData* data = new RadioMimeData; RadioMimeData* data = new RadioMimeData;
data->setUrls(urls); data->setUrls(urls);
data->services = services; data->items = items;
data->titles = titles;
return data; return data;
} }

View File

@ -21,7 +21,9 @@ class RadioService : public QObject {
virtual RadioItem* CreateRootItem(RadioItem* parent) = 0; virtual RadioItem* CreateRootItem(RadioItem* parent) = 0;
virtual void LazyPopulate(RadioItem* item) = 0; virtual void LazyPopulate(RadioItem* item) = 0;
virtual QList<RadioItem::PlaylistData> DataForItem(RadioItem* item) = 0; virtual QUrl UrlForItem(const RadioItem* item) const = 0;
virtual QString TitleForItem(const RadioItem* item) const = 0;
virtual void ShowContextMenu(RadioItem* item, const QPoint& global_pos) { virtual void ShowContextMenu(RadioItem* item, const QPoint& global_pos) {
Q_UNUSED(item); Q_UNUSED(global_pos); } Q_UNUSED(item); Q_UNUSED(global_pos); }