1
/* This file is part of Clementine.
2
Copyright 2010, David Sansome <me@davidsansome.com>
4
Clementine is free software: you can redistribute it and/or modify
5
it under the terms of the GNU General Public License as published by
6
the Free Software Foundation, either version 3 of the License, or
7
(at your option) any later version.
9
Clementine is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU General Public License for more details.
14
You should have received a copy of the GNU General Public License
15
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
18
#include "digitallyimportedservicebase.h"
19
#include "icecastservice.h"
20
#include "jamendoservice.h"
21
#include "magnatuneservice.h"
22
#include "internetmimedata.h"
23
#include "internetmodel.h"
24
#include "internetservice.h"
25
#include "savedradio.h"
26
#include "somafmservice.h"
27
#include "groovesharkservice.h"
28
#include "core/logging.h"
29
#include "core/mergedproxymodel.h"
30
#include "smartplaylists/generatormimedata.h"
33
#include "lastfmservice.h"
36
#include "spotifyservice.h"
42
using smart_playlists::Generator;
43
using smart_playlists::GeneratorMimeData;
44
using smart_playlists::GeneratorPtr;
46
QMap<QString, InternetService*>* InternetModel::sServices = NULL;
48
InternetModel::InternetModel(BackgroundThread<Database>* db_thread,
49
TaskManager* task_manager, PlayerInterface* player,
50
CoverProviders* cover_providers,
51
GlobalSearch* global_search, QObject* parent)
52
: QStandardItemModel(parent),
53
db_thread_(db_thread),
54
merged_model_(new MergedProxyModel(this)),
55
task_manager_(task_manager),
57
cover_providers_(cover_providers),
58
global_search_(global_search)
61
sServices = new QMap<QString, InternetService*>;
63
Q_ASSERT(sServices->isEmpty());
65
merged_model_->setSourceModel(this);
67
AddService(new DigitallyImportedService(this));
68
AddService(new IcecastService(this));
69
AddService(new JamendoService(this));
71
AddService(new LastFMService(this));
73
AddService(new GroovesharkService(this));
74
AddService(new MagnatuneService(this));
75
AddService(new SavedRadio(this));
76
AddService(new SkyFmService(this));
77
AddService(new SomaFMService(this));
79
AddService(new SpotifyService(this));
83
void InternetModel::AddService(InternetService *service) {
84
QStandardItem* root = service->CreateRootItem();
86
qLog(Warning) << "Internet service" << service->name() << "did not return a root item";
90
root->setData(Type_Service, Role_Type);
91
root->setData(QVariant::fromValue(service), Role_Service);
93
invisibleRootItem()->appendRow(root);
94
qLog(Debug) << "Adding internet service:" << service->name();
95
sServices->insert(service->name(), service);
97
connect(service, SIGNAL(StreamError(QString)), SIGNAL(StreamError(QString)));
98
connect(service, SIGNAL(StreamMetadataFound(QUrl,Song)), SIGNAL(StreamMetadataFound(QUrl,Song)));
99
connect(service, SIGNAL(OpenSettingsAtPage(SettingsDialog::Page)), SIGNAL(OpenSettingsAtPage(SettingsDialog::Page)));
100
connect(service, SIGNAL(AddToPlaylistSignal(QMimeData*)), SIGNAL(AddToPlaylist(QMimeData*)));
101
connect(service, SIGNAL(destroyed()), SLOT(ServiceDeleted()));
103
service->ReloadSettings();
106
void InternetModel::RemoveService(InternetService* service) {
107
if (!sServices->contains(service->name()))
110
// Find and remove the root item that this service created
111
for (int i=0 ; i<invisibleRootItem()->rowCount() ; ++i) {
112
QStandardItem* item = invisibleRootItem()->child(i);
113
if (!item || item->data(Role_Service).value<InternetService*>() == service) {
114
invisibleRootItem()->removeRow(i);
119
// Remove the service from the list
120
sServices->remove(service->name());
122
// Disconnect the service
123
disconnect(service, 0, this, 0);
126
void InternetModel::ServiceDeleted() {
127
InternetService* service = qobject_cast<InternetService*>(sender());
129
RemoveService(service);
132
InternetService* InternetModel::ServiceByName(const QString& name) {
133
if (sServices->contains(name))
134
return sServices->value(name);
138
InternetService* InternetModel::ServiceForItem(const QStandardItem* item) const {
139
return ServiceForIndex(indexFromItem(item));
142
InternetService* InternetModel::ServiceForIndex(const QModelIndex& index) const {
143
QModelIndex current_index = index;
144
while (current_index.isValid()) {
145
InternetService* service = current_index.data(Role_Service).value<InternetService*>();
149
current_index = current_index.parent();
154
Qt::ItemFlags InternetModel::flags(const QModelIndex& index) const {
155
Qt::ItemFlags flags = Qt::ItemIsSelectable |
157
Qt::ItemIsDropEnabled;
158
if (IsPlayable(index)) {
159
flags |= Qt::ItemIsDragEnabled;
164
bool InternetModel::hasChildren(const QModelIndex& parent) const {
165
if (parent.data(Role_CanLazyLoad).toBool())
167
return QStandardItemModel::hasChildren(parent);
170
int InternetModel::rowCount(const QModelIndex& parent) const {
171
if (parent.data(Role_CanLazyLoad).toBool()) {
172
QStandardItem* item = itemFromIndex(parent);
173
InternetService* service = ServiceForItem(item);
175
item->setData(false, Role_CanLazyLoad);
176
service->LazyPopulate(item);
180
return QStandardItemModel::rowCount(parent);
183
bool InternetModel::IsPlayable(const QModelIndex& index) const {
184
QVariant behaviour = index.data(Role_PlayBehaviour);
185
if (!behaviour.isValid())
188
PlayBehaviour pb = PlayBehaviour(behaviour.toInt());
189
return (pb == PlayBehaviour_SingleItem || PlayBehaviour_UseSongLoader);
192
QStringList InternetModel::mimeTypes() const {
193
return QStringList() << "text/uri-list";
196
QMimeData* InternetModel::mimeData(const QModelIndexList& indexes) const {
197
// Special case for when the user double clicked on a special item.
198
if (indexes.count() == 1 &&
199
indexes[0].data(Role_PlayBehaviour).toInt() ==
200
PlayBehaviour_DoubleClickAction) {
201
InternetModel::ServiceForIndex(indexes[0])->ItemDoubleClicked(itemFromIndex(indexes[0]));
205
if (indexes.count() == 1 &&
206
indexes[0].data(Role_Type).toInt() == Type_SmartPlaylist) {
207
GeneratorPtr generator =
208
InternetModel::ServiceForIndex(indexes[0])->CreateGenerator(itemFromIndex(indexes[0]));
211
GeneratorMimeData* data = new GeneratorMimeData(generator);
212
data->setData(LibraryModel::kSmartPlaylistsMimeType, QByteArray());
213
data->name_for_new_playlist_ = this->data(indexes.first()).toString();
218
QModelIndexList new_indexes;
220
QModelIndex last_valid_index;
221
foreach (const QModelIndex& index, indexes) {
222
if (!IsPlayable(index))
225
last_valid_index = index;
226
if (index.data(Role_Type).toInt() == Type_UserPlaylist) {
230
QModelIndex child = index.child(row, column);
231
while (child.isValid()) {
232
new_indexes << child;
233
urls << child.data(Role_Url).toUrl();
234
child = index.child(++row, column);
237
new_indexes = indexes;
238
urls << index.data(Role_Url).toUrl();
245
InternetMimeData* data = new InternetMimeData(this);
247
data->indexes = new_indexes;
248
data->name_for_new_playlist_ = InternetModel::ServiceForIndex(last_valid_index)->name();
253
bool InternetModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) {
254
if (action == Qt::IgnoreAction) {
257
if (parent.data(Role_CanBeModified).toBool()) {
258
InternetModel::ServiceForIndex(parent)->DropMimeData(data, parent);
264
void InternetModel::ShowContextMenu(const QModelIndex& merged_model_index,
265
const QPoint& global_pos) {
266
InternetService* service = ServiceForIndex(merged_model_index);
268
service->ShowContextMenu(merged_model_->mapToSource(merged_model_index), global_pos);
271
void InternetModel::ReloadSettings() {
272
foreach (InternetService* service, sServices->values()) {
273
service->ReloadSettings();