1 /****************************************************************************************
2 * Copyright (c) 2007 Nikolaj Hald Nielsen <nhn@kde.org> *
3 * *
4 * This program is free software; you can redistribute it and/or modify it under *
5 * the terms of the GNU General Public License as published by the Free Software *
6 * Foundation; either version 2 of the License, or (at your option) any later *
7 * version. *
8 * *
9 * This program is distributed in the hope that it will be useful, but WITHOUT ANY *
10 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
11 * PARTICULAR PURPOSE. See the GNU General Public License for more details. *
12 * *
13 * You should have received a copy of the GNU General Public License along with *
14 * this program. If not, see <http://www.gnu.org/licenses/>. *
15 ****************************************************************************************/
16
17 #include "ScriptableService.h"
18
19 #include "scripting/scriptmanager/ScriptManager.h"
20 #include "browsers/CollectionTreeItem.h"
21 #include "browsers/SingleCollectionTreeItemModel.h"
22 #include "browsers/servicebrowser/ServiceBrowser.h"
23 #include "core/support/Amarok.h"
24 #include "core/support/Debug.h"
25 #include "services/scriptable/ScriptableServiceCollectionTreeModel.h"
26 #include "services/scriptable/ScriptableServiceInfoParser.h"
27 #include "widgets/SearchWidget.h"
28
29 #include <QStandardPaths>
30
31 using namespace Meta;
32
ScriptableService(const QString & name)33 ScriptableService::ScriptableService( const QString & name )
34 : ServiceBase( name, nullptr )
35 , m_polished( false )
36 , m_name( name )
37 , m_trackIdCounter( 0 )
38 , m_albumIdCounter( 0 )
39 , m_artistIdCounter( 0 )
40 , m_genreIdCounter( 0 )
41 {
42 DEBUG_BLOCK
43 debug() << "creating ScriptableService " << name;
44 m_collection = nullptr;
45 m_bottomPanel->hide();
46 }
47
~ScriptableService()48 ScriptableService::~ScriptableService()
49 {
50 m_collection->deleteLater();
51 }
52
init(int levels,const QString & rootHtml,bool showSearchBar)53 void ScriptableService::init( int levels, const QString & rootHtml, bool showSearchBar )
54 {
55 DEBUG_BLOCK
56 m_levels = levels;
57 m_rootHtml = rootHtml;
58 m_hasSearchBar = showSearchBar;
59 m_searchWidget->showAdvancedButton( false );
60 setInfoParser( new ScriptableServiceInfoParser( m_name ) );
61 m_collection = new Collections::ScriptableServiceCollection( m_name );
62 m_collection->setLevels( levels );
63
64 if ( !showSearchBar )
65 m_searchWidget->hide();
66 }
67
collection()68 Collections::ServiceCollection * ScriptableService::collection()
69 {
70 return m_collection;
71 }
72
73
insertItem(int level,int parentId,const QString & name,const QString & infoHtml,const QString & callbackData,const QString & playableUrl,const QString & albumOverride,const QString & artistOverride,const QString & genreOverride,const QString & composerOverride,int yearOverride,const QString & coverUrl)74 int ScriptableService::insertItem( int level, int parentId, const QString & name, const QString & infoHtml, const QString & callbackData, const QString & playableUrl,
75 const QString & albumOverride, const QString & artistOverride, const QString & genreOverride,
76 const QString & composerOverride, int yearOverride, const QString &coverUrl )
77 {
78
79 /*
80 please don't remove this block as I regularly need it for debugging - nhn
81 DEBUG_BLOCK
82 debug() << "level: " << level;
83 debug() << "parentId: " << parentId;
84 debug() << "name: " << name;
85 debug() << "infoHtml: " << infoHtml;
86 debug() << "callbackData: " << callbackData;
87 debug() << "playableUrl: " << playableUrl;
88
89 debug() << "albumOverride: " << albumOverride;
90 debug() << "artistOverride: " << artistOverride;
91 debug() << "coverUrl: " << coverUrl;*/
92
93 if ( ( level +1 > m_levels ) || level < 0 )
94 return -1;
95
96 switch ( level ) {
97
98 case 0:
99 {
100 if( !callbackData.isEmpty() || playableUrl.isEmpty() )
101 return -1;
102
103 AmarokSharedPointer<ScriptableServiceTrack> track( new ScriptableServiceTrack( name ) );
104 track->setAlbumId( parentId );
105 track->setUidUrl( playableUrl );
106 track->setServiceName( m_name );
107 track->setDescription( infoHtml );
108
109 if ( !m_customEmblem.isNull() )
110 track->setServiceEmblem( m_customEmblem );
111 else
112 track->setServiceEmblem( QPixmap( QStandardPaths::locate( QStandardPaths::GenericDataLocation, QStringLiteral("amarok/images/emblem-scripted.png") ) ) );
113
114 if ( !m_customScalableEmblem.isEmpty() )
115 track->setServiceScalableEmblem( m_customScalableEmblem );
116 else
117 track->setServiceEmblem( QStandardPaths::locate( QStandardPaths::GenericDataLocation, QStringLiteral("amarok/images/emblem-scripted-scalable.svgz") ) );
118
119 if ( !albumOverride.isEmpty() )
120 track->setAlbumName( albumOverride );
121 if ( !artistOverride.isEmpty() )
122 track->setArtistName( artistOverride );
123 if ( !genreOverride.isEmpty() )
124 track->setGenreName( genreOverride );
125 if ( !composerOverride.isEmpty() )
126 track->setComposerName( composerOverride );
127 if ( yearOverride != 0 )
128 track->setYearNumber( yearOverride );
129 if ( !coverUrl.isEmpty() )
130 track->setCustomAlbumCoverUrl( coverUrl );
131
132 return addTrack( track.data() );
133 break;
134
135 } case 1:
136 {
137 if ( callbackData.isEmpty() || !playableUrl.isEmpty() )
138 return -1;
139
140 ScriptableServiceAlbum * album = new ScriptableServiceAlbum( name );
141 album->setCallbackString( callbackData );
142 album->setArtistId( parentId );
143 album->setDescription( infoHtml );
144 album->setServiceName( m_name );
145 //debug() << "setting coverUrl: " << coverUrl;
146 album->setCoverUrl( coverUrl );
147
148 album->setServiceName( m_name );
149 album->setDescription( infoHtml );
150
151 if ( !m_customEmblem.isNull() )
152 album->setServiceEmblem( m_customEmblem );
153 else
154 album->setServiceEmblem( QPixmap( QStandardPaths::locate( QStandardPaths::GenericDataLocation, QStringLiteral("amarok/images/emblem-scripted.png") ) ) );
155
156 if ( !m_customScalableEmblem.isEmpty() )
157 album->setServiceScalableEmblem( m_customScalableEmblem );
158 else
159 album->setServiceEmblem( QStandardPaths::locate( QStandardPaths::GenericDataLocation, QStringLiteral("amarok/images/emblem-scripted-scalable.svgz") ) );
160
161 return addAlbum( album );
162
163 } case 2:
164 {
165 if ( callbackData.isEmpty() || !playableUrl.isEmpty() )
166 return -1;
167
168 ScriptableServiceArtist * artist = new ScriptableServiceArtist( name );
169 artist->setCallbackString( callbackData );
170 artist->setGenreId( parentId );
171 artist->setDescription( infoHtml );
172 artist->setServiceName( m_name );
173
174 artist->setServiceName( m_name );
175 artist->setDescription( infoHtml );
176
177 if ( !m_customEmblem.isNull() )
178 artist->setServiceEmblem( m_customEmblem );
179 else
180 artist->setServiceEmblem( QPixmap( QStandardPaths::locate( QStandardPaths::GenericDataLocation, QStringLiteral("amarok/images/emblem-scripted.png") ) ) );
181
182 if ( !m_customScalableEmblem.isEmpty() )
183 artist->setServiceScalableEmblem( m_customScalableEmblem );
184 else
185 artist->setServiceEmblem( QStandardPaths::locate( QStandardPaths::GenericDataLocation, QStringLiteral("amarok/images/emblem-scripted-scalable.svgz") ) );
186
187
188 return addArtist( artist );
189
190 } case 3:
191 {
192
193 if ( callbackData.isEmpty() || !playableUrl.isEmpty() || parentId != -1 )
194 return -1;
195
196 ScriptableServiceGenre * genre = new ScriptableServiceGenre( name );
197 genre->setCallbackString( callbackData );
198 genre->setDescription( infoHtml );
199 genre->setServiceName( m_name );
200
201 genre->setServiceName( m_name );
202 genre->setDescription( infoHtml );
203
204 if ( !m_customEmblem.isNull() )
205 genre->setServiceEmblem( m_customEmblem );
206 else
207 genre->setServiceEmblem( QPixmap( QStandardPaths::locate( QStandardPaths::GenericDataLocation, QStringLiteral("amarok/images/emblem-scripted.png") ) ) );
208
209 if ( !m_customScalableEmblem.isEmpty() )
210 genre->setServiceScalableEmblem( m_customScalableEmblem );
211 else
212 genre->setServiceEmblem( QStandardPaths::locate( QStandardPaths::GenericDataLocation, QStringLiteral("amarok/images/emblem-scripted-scalable.svgz") ) );
213
214
215 return addGenre( genre );
216
217 }
218 }
219 return -1;
220 }
221
222
addTrack(ScriptableServiceTrack * track)223 int ScriptableService::addTrack( ScriptableServiceTrack * track )
224 {
225 int artistId = -1;
226 int genreId = -1;
227
228 TrackPtr trackPtr = TrackPtr( track );
229 m_collection->acquireWriteLock();
230 m_collection->addTrack( trackPtr );
231 m_collection->releaseLock();
232
233 m_trackIdCounter++;
234 track->setId( m_trackIdCounter );
235
236
237 int albumId = track->albumId();
238
239 //handle albums
240 if ( m_levels > 1 ) {
241
242 if ( !m_ssAlbumIdMap.contains( albumId ) ){
243 return -1;
244 }
245
246 ScriptableServiceAlbum * album = m_ssAlbumIdMap.value( albumId );
247
248 track->setAlbum( album->prettyName() );
249 track->setAlbumPtr( AlbumPtr( album ) );
250 album->addTrack( trackPtr );
251
252 artistId = album->artistId();
253
254 }
255
256 if ( m_levels > 2 ) {
257
258 if ( !m_ssArtistIdMap.contains( artistId ) ) {
259 return -1;
260 }
261
262 ScriptableServiceArtist * artist = m_ssArtistIdMap.value( artistId );
263 track->setArtist( artist->prettyName() );
264 track->setArtist( ArtistPtr( artist ) );
265 artist->addTrack( trackPtr );
266
267 genreId = artist->genreId();
268 }
269
270 if ( m_levels == 4) {
271
272 if ( !m_ssGenreIdMap.contains( genreId ) ) {
273 return -1;
274 }
275
276 ScriptableServiceGenre * genre = m_ssGenreIdMap.value( genreId );
277 track->setGenre( genre->prettyName() );
278 track->setGenre( GenrePtr( genre ) );
279 genre->addTrack( trackPtr );
280
281 }
282
283 m_ssTrackIdMap.insert( m_trackIdCounter, track );
284 m_collection->acquireWriteLock();
285 m_collection->addTrack( trackPtr );
286 m_collection->releaseLock();
287
288 //m_collection->emitUpdated();
289
290 return m_trackIdCounter;
291 }
292
addAlbum(ScriptableServiceAlbum * album)293 int ScriptableService::addAlbum( ScriptableServiceAlbum * album )
294 {
295 int artistId = album->artistId();
296 if ( m_levels > 2 && !m_ssArtistIdMap.contains( artistId ) ) {
297 delete album;
298 return -1;
299 }
300
301 album->setAlbumArtist( ArtistPtr( m_ssArtistIdMap.value( artistId ) ) );
302
303 AlbumPtr albumPtr = AlbumPtr( album );
304 m_albumIdCounter++;
305 album->setId( m_albumIdCounter );
306 m_ssAlbumIdMap.insert( m_albumIdCounter, album );
307 m_collection->acquireWriteLock();
308 m_collection->addAlbum( albumPtr );
309 m_collection->releaseLock();
310 //m_collection->emitUpdated();
311 return m_albumIdCounter;
312 }
313
addArtist(Meta::ScriptableServiceArtist * artist)314 int ScriptableService::addArtist( Meta::ScriptableServiceArtist * artist )
315 {
316 int genreId = artist->genreId();
317 if ( m_levels > 3 && !m_ssGenreIdMap.contains( genreId ) ) {
318 delete artist;
319 return -1;
320 }
321
322 ArtistPtr artistPtr = ArtistPtr( artist );
323 m_artistIdCounter++;
324 artist->setId( m_artistIdCounter );
325 m_ssArtistIdMap.insert( m_artistIdCounter, artist );
326 m_collection->acquireWriteLock();
327 m_collection->addArtist( artistPtr );
328 m_collection->releaseLock();
329
330 return m_artistIdCounter;
331
332 }
333
addGenre(Meta::ScriptableServiceGenre * genre)334 int ScriptableService::addGenre( Meta::ScriptableServiceGenre * genre )
335 {
336 GenrePtr genrePtr = GenrePtr( genre );
337 m_genreIdCounter++;
338
339 //debug() << "adding genre: " << genre->name() << ", with id: " << m_genreIdCounter;
340
341 genre->setId( m_genreIdCounter );
342 m_ssGenreIdMap.insert( m_genreIdCounter, genre );
343 m_collection->acquireWriteLock();
344 m_collection->addGenre( genrePtr );
345 m_collection->releaseLock();
346
347 return m_genreIdCounter;
348 }
349
donePopulating(int parentId)350 void ScriptableService::donePopulating( int parentId )
351 {
352 m_collection->donePopulating( parentId );
353 }
354
polish()355 void ScriptableService::polish()
356 {
357
358 if ( !m_polished ) {
359 QList<CategoryId::CatMenuId> viewLevels;
360
361 switch ( m_levels ) {
362 case 1:
363 break;
364 case 2:
365 viewLevels << CategoryId::Album;
366 break;
367 case 3:
368 viewLevels << CategoryId::Artist << CategoryId::Album;
369 break;
370 case 4:
371 viewLevels << CategoryId::Genre << CategoryId::Artist << CategoryId::Album;
372 break;
373 default:
374 return;
375 }
376
377 m_contentView->setModel( new ScriptableServiceCollectionTreeModel( m_collection, viewLevels ) );
378 m_polished = true;
379
380 }
381
382 infoChanged( m_rootHtml );
383 }
384
setCustomEmblem(const QPixmap & emblem)385 void ScriptableService::setCustomEmblem( const QPixmap &emblem )
386 {
387 m_customEmblem = emblem;
388 }
389
customEmblem()390 QPixmap ScriptableService::customEmblem()
391 {
392 return m_customEmblem;
393 }
394
395
customScalableEmblem()396 QString ScriptableService::customScalableEmblem()
397 {
398 return m_customScalableEmblem;
399 }
400
401
setCustomScalableEmblem(const QString & emblemPath)402 void ScriptableService::setCustomScalableEmblem ( const QString& emblemPath )
403 {
404 m_customScalableEmblem = emblemPath;
405 }
406
407
408
setCurrentInfo(const QString & info)409 void ScriptableService::setCurrentInfo( const QString & info )
410 {
411 infoChanged( info );
412 }
413
414
415
416
417
418