1 /***************************************************************************
2 * copyright : (c) 2004 Pierpaolo Di Panfilo *
3 * (c) 2005-2006 Seb Ruiz <me@sebruiz.net> *
4 * (c) 2006 Bart Cerneels <bart.cerneels@gmail.com> *
5 * (c) 2006 Adam Pigg <adam@piggz.co.uk> *
6 * (c) 2006 Bonne Eggleston <b.eggleston@gmail.com> *
7 * See COPYING file for licensing information *
8 ***************************************************************************/
10 #ifndef PLAYLISTBROWSERITEM_H
11 #define PLAYLISTBROWSERITEM_H
13 #include "dynamicmode.h"
14 #include "podcastbundle.h"
15 #include "podcastsettings.h"
17 #include <kdialog.h> // StreamEditor baseclass
19 #include <klineedit.h>
20 #include <k3listview.h>
26 #include <q3ptrlist.h>
27 #include <QTimer> // Podcast loading animation
30 #include <Q3ValueList>
31 #include <QCustomEvent>
35 class PlaylistTrackItem
;
38 namespace KIO
{ class Job
; class TransferJob
; class CopyJob
; } //podcast downloads
42 * 1000 - PlaylistCategory
43 * 1001 - PlaylistEntry
44 * 1002 - PlaylistTrackItem
46 * 1004 - SmartPlaylist
47 * 1005 - DynamicEntry (Dynamic)
48 * 1006 - PodcastChannel
49 * 1007 - PodcastEpisode
53 /* A base class to be able to use polymorphism and avoid tons of casts */
54 class PlaylistBrowserEntry
: public QObject
, public K3ListViewItem
58 PlaylistBrowserEntry( Q3ListViewItem
*parent
, Q3ListViewItem
*after
)
59 : K3ListViewItem( parent
, after
) { m_kept
= true; }
60 PlaylistBrowserEntry( Q3ListView
*parent
, Q3ListViewItem
*after
)
61 : K3ListViewItem( parent
, after
) { m_kept
= true; }
62 PlaylistBrowserEntry( Q3ListViewItem
*parent
, Q3ListViewItem
*after
, const QString
&name
)
63 : K3ListViewItem( parent
, after
, name
) { m_kept
= true; }
65 virtual QDomElement
xml() const { return QDomElement(); }
66 Q3ListViewItem
* parent() const { return K3ListViewItem::parent(); }
68 bool isKept() const { return m_kept
; } // if kept == true, then it will be saved
69 void setKept( bool k
); // to the cache files. If false, non-renameable
71 virtual void updateInfo();
72 virtual void setDynamic( bool ) {};
75 virtual void slotDoubleClicked();
76 virtual void slotRenameItem();
77 virtual void slotPostRenameItem( const QString newName
);
78 virtual void showContextMenu( const QPoint
& ) {};
81 virtual int compare( Q3ListViewItem
*, int, bool ) const; //reimplemented
83 /** Interval of the download pixmap animation, in milliseconds */
84 static const int ANIMATION_INTERVAL
= 250;
90 class DynamicEntry
: public PlaylistBrowserEntry
, public DynamicMode
94 DynamicEntry( Q3ListViewItem
*parent
, Q3ListViewItem
*after
, const QString
&title
);
95 DynamicEntry( Q3ListViewItem
*parent
, Q3ListViewItem
*after
, const QDomElement
&xmlDefinition
);
98 virtual QString
text( int column
) const;
100 virtual QDomElement
xml() const;
102 static const int RTTI
= 1005;
103 int rtti() const { return RTTI
; }
106 virtual void slotDoubleClicked();
107 virtual void showContextMenu( const QPoint
& );
110 class PlaylistCategory
: public PlaylistBrowserEntry
114 PlaylistCategory( Q3ListView
*parent
, Q3ListViewItem
*after
, const QString
&, bool isFolder
=false );
115 PlaylistCategory( PlaylistCategory
*parent
, Q3ListViewItem
*after
, const QString
&, bool isFolder
=true );
116 PlaylistCategory( Q3ListView
*parent
, Q3ListViewItem
*after
, const QDomElement
&xmlDefinition
, bool isFolder
=false);
117 PlaylistCategory( PlaylistCategory
*parent
, Q3ListViewItem
*after
, const QDomElement
&xmlDefinition
);
118 PlaylistCategory( PlaylistCategory
*parent
, Q3ListViewItem
*after
, const QString
&t
, const int id
);
120 ~PlaylistCategory() { };
122 const QString
&title() const { return m_title
; }
123 bool isFolder() { return m_folder
; }
125 void paintCell( QPainter
*, const QColorGroup
&, int, int, int );
127 void setId( const int id
) { m_id
= id
; }
128 const int id() const { return m_id
; }
130 virtual QDomElement
xml() const;
132 int rtti() const { return RTTI
; }
133 static const int RTTI
= 1000; //category item
136 virtual void slotDoubleClicked();
137 virtual void slotRenameItem();
138 virtual void showContextMenu( const QPoint
& );
141 void okRename( int col
);
145 void setXml( const QDomElement
&xml
);
153 class PlaylistEntry
: public PlaylistBrowserEntry
157 friend class PlaylistTrackItem
;
158 friend class TrackItemInfo
;
159 friend class PlaylistCategory
;
162 PlaylistEntry( Q3ListViewItem
*parent
, Q3ListViewItem
*after
, const KUrl
&, int tracks
=0, int length
=0 );
163 PlaylistEntry( Q3ListViewItem
*parent
, Q3ListViewItem
*after
, const QDomElement
&xmlDefinition
);
166 void sortChildItems ( int /*column*/, bool /*ascending*/ ) { /* Don't sort its children */ }; //reimplemented
170 const KUrl
&url() const { return m_url
; }
171 void setUrl( const QString
&u
) { m_url
.setPath( u
); }
172 int trackCount() const { return m_trackCount
; }
173 int length() const { return m_length
; }
174 bool isDynamic() const { return m_dynamic
; }
175 bool isLoaded() const { return m_loaded
; }
177 void setDynamic( bool );
179 int compare( Q3ListViewItem
* i
, int col
) const; //reimpl.
180 KUrl::List
tracksURL(); //returns the list of tracks url
181 void insertTracks( Q3ListViewItem
*after
, KUrl::List list
);
182 void insertTracks( Q3ListViewItem
*after
, Q3ValueList
<MetaBundle
> bundles
);
183 // isLast is used to avoid saving the playlist to disk every time a track is removed
184 // when removing a list of tracks from the playlist
185 void removeTrack( Q3ListViewItem
*item
, bool isLast
= true );
187 //returns a list of track information
188 Q3PtrList
<TrackItemInfo
> trackList() const { return m_trackList
; }
189 Q3PtrList
<TrackItemInfo
> droppedTracks() const { return tmp_droppedTracks
; }
191 void setOpen( bool );
193 void paintCell( QPainter
*, const QColorGroup
&, int, int, int );
195 virtual QDomElement
xml() const;
197 virtual void updateInfo();
199 //rtti is used to distinguish different kinds of list view items
200 int rtti() const { return RTTI
; }
201 static const int RTTI
= 1001; //playlist item
204 virtual void slotDoubleClicked();
205 virtual void slotPostRenameItem( const QString newName
);
206 virtual void showContextMenu( const QPoint
& );
209 void startingLoading();
213 void slotAnimation();
216 void customEvent( QEvent
* e
);
217 void startAnimation();
218 void stopAnimation();
220 KUrl m_url
; //playlist url
221 int m_length
; //total length in seconds
222 int m_trackCount
; //track counter
223 Q3PtrList
<TrackItemInfo
> m_trackList
; //tracks in playlist
224 Q3PtrList
<TrackItemInfo
> tmp_droppedTracks
; //tracks dropped to the playlist while it wasn't been loaded
226 bool m_loaded
; //playlist loaded
227 bool m_dynamic
; //the playlist is scheduled for dynamic mode rotation
228 QPixmap
*m_loading1
, *m_loading2
; //icons for loading animation
229 QTimer m_animationTimer
;
231 PlaylistTrackItem
*m_lastTrack
;
234 class PlaylistTrackItem
: public PlaylistBrowserEntry
237 friend class TrackItemInfo
;
240 PlaylistTrackItem( Q3ListViewItem
*parent
, Q3ListViewItem
*after
, TrackItemInfo
*info
);
243 TrackItemInfo
*trackInfo() const { return m_trackInfo
; }
245 int rtti() const { return RTTI
; }
246 static const int RTTI
= 1002; //track item
249 virtual void slotDoubleClicked();
250 virtual void slotRenameItem() { /* Do nothing */ };
251 virtual void showContextMenu( const QPoint
& );
254 TrackItemInfo
*m_trackInfo
;
257 /// Stored in the database
258 class PodcastEpisode
: public PlaylistBrowserEntry
263 PodcastEpisode( Q3ListViewItem
*parent
, Q3ListViewItem
*after
, const QDomElement
&xml
,
264 const int feedType
, const bool &isNew
=false );
265 PodcastEpisode( Q3ListViewItem
*parent
, Q3ListViewItem
*after
, PodcastEpisodeBundle
&bundle
);
267 void downloadMedia();
268 void setOnDisk( bool d
= true );
269 Q3ListViewItem
*itemChannel() { return m_parent
; }
272 const bool isNew() const { return m_bundle
.isNew(); }
274 void setNew( const bool &n
= true );
275 void setListened( const bool &n
= true ) { setNew( !n
); }
278 const int dBId() const { return m_bundle
.dBId(); }
279 const KUrl
url() const { return m_bundle
.url(); }
280 const QString
title() const { return m_bundle
.title(); }
281 const QString
author() const { return m_bundle
.author(); }
282 const QString
date() const { return m_bundle
.date(); }
283 const QString
type() const { return m_bundle
.type(); }
284 const QString
description() const { return m_bundle
.description(); }
285 const QString
guid() const { return m_bundle
.guid(); }
286 const int duration() const { return m_bundle
.duration(); }
287 const KUrl
&localUrl() const { return m_localUrl
; }
288 void setLocalUrlBase( const QString
&s
);
289 void setLocalUrl( const KUrl
&localUrl
);
292 void paintCell( QPainter
*, const QColorGroup
&, int, int, int );
294 virtual void updateInfo();
296 void addToMediaDevice();
298 int rtti() const { return RTTI
; }
299 static const int RTTI
= 1007; //PodcastEpisode
300 static void createLocalDir( const KUrl
&localDir
);
303 void downloadFinished();
304 void downloadAborted();
307 const bool isOnDisk();
308 virtual void slotDoubleClicked();
309 virtual void slotRenameItem() { /* Do nothing */ };
310 virtual void showContextMenu( const QPoint
& );
313 void abortDownload();
314 void downloadResult( KJob
* transferJob
);
315 void slotAnimation();
316 void redirected( KIO::Job
* job
,const KUrl
& redirectedUrl
);
319 enum FeedType
{ RSS
=0, ATOM
=1 };
321 virtual int compare( Q3ListViewItem
*, int, bool ) const; //reimplemented
323 void associateWithLocalFile();
325 void startAnimation();
326 void stopAnimation();
329 Q3ListViewItem
*m_parent
; //podcast channel it belongs to
330 PodcastEpisodeBundle m_bundle
;
334 QTimer m_animationTimer
;
337 KIO::StoredTransferJob
* m_podcastEpisodeJob
;
340 bool m_downloaded
; //marked as downloaded in cached xml
344 /// Stored in the database
345 class PodcastChannel
: public PlaylistBrowserEntry
350 PodcastChannel( Q3ListViewItem
*parent
, Q3ListViewItem
*after
, const KUrl
&url
,
351 const QDomNode
&channelSettings
);
352 PodcastChannel( Q3ListViewItem
*parent
, Q3ListViewItem
*after
, const KUrl
&url
);
353 PodcastChannel( Q3ListViewItem
*parent
, Q3ListViewItem
*after
, const KUrl
&url
,
354 const QDomNode
&channelSettings
, const QDomDocument
&xml
);
355 PodcastChannel( Q3ListViewItem
*parent
, Q3ListViewItem
*after
, const PodcastChannelBundle
&pcb
);
357 enum MediaFetch
{ STREAM
=0, AUTOMATIC
=1 };
359 void setNew( const bool n
= true );
360 bool hasNew() const { return m_new
; }
361 // iterate over all children and explicitly check if there are any episodes which have not been listened
362 // to. Mark the channel as new/listened after doing this.
363 void checkAndSetNew();
365 void setListened( const bool n
= true ); // over rides each child so it has been listened
367 void setOpen( bool open
); // if !m_polished, load the children. Lazy loading to improve start times
369 const bool isPolished() const { return m_polished
; }
375 const KUrl
&url() const { return m_url
; }
376 const KUrl
link() const { return m_bundle
.link(); }
377 const QString
title() const { return m_bundle
.title(); }
378 const QString
description() const { return m_bundle
.description(); }
379 const QString
copyright() const { return m_bundle
.copyright(); }
381 const bool autoscan() const { return m_bundle
.autoscan(); }
382 const bool autotransfer() const { return m_bundle
.autotransfer(); }
383 const int fetchType() const { return m_bundle
.fetchType(); }
384 const bool hasPurge() const { return m_bundle
.hasPurge(); }
385 const int purgeCount() const { return m_bundle
.purgeCount(); }
386 const QString
&saveLocation() const { return m_bundle
.saveLocation(); }
387 PodcastSettings
*getSettings() const
389 return new PodcastSettings( title(), saveLocation(),
390 autoscan(), fetchType(), autotransfer(),
391 hasPurge(), purgeCount() );
394 void setParent( PlaylistCategory
*newParent
);
395 void setSettings( PodcastSettings
*settings
);
396 void setXml( const QDomNode
&xml
, const int feedType
);
398 virtual void updateInfo();
400 int rtti() const { return RTTI
; }
401 static const int RTTI
= 1006; //podcastchannel
404 virtual void slotDoubleClicked();
405 virtual void slotRenameItem() { /* Do nothing */ };
406 virtual void showContextMenu( const QPoint
& );
410 void downloadChildQueue();
411 void fetchResult( KIO::Job
* job
);
412 void slotAnimation();
415 enum FeedType
{ RSS
=0, ATOM
=1 };
416 static const int EPISODE_LIMIT
= 10; //Maximum number of episodes initially shown
418 bool containsItem( QDomElement xml
);
419 void downloadChildren();
420 const bool episodeExists( const QDomNode
&xml
, const int feedType
);
422 void restorePurged();
423 void removeChildren();
424 void setDOMSettings( const QDomNode
&channelSettings
);
425 void startAnimation();
426 void stopAnimation();
428 PodcastChannelBundle m_bundle
;
430 /// loading all of the podcast episodes during startup can be very inefficient.
431 /// When the user expands the podcast for the first time, we load up the episodes.
434 KUrl m_url
; //remote xml url
437 QTimer m_animationTimer
;
442 KIO::TransferJob
*m_podcastJob
;
443 PlaylistCategory
*m_parent
; // category it belongs to
444 QString m_podcastCurrentUrl
;
445 Q3PtrList
<PodcastEpisode
> m_podcastDownloadQueue
;
446 bool m_settingsValid
;
449 class StreamEntry
: public PlaylistBrowserEntry
453 StreamEntry( Q3ListViewItem
*parent
, Q3ListViewItem
*after
, const KUrl
&, const QString
&t
);
454 StreamEntry( Q3ListViewItem
*parent
, Q3ListViewItem
*after
, const QDomElement
&xmlDefinition
);
457 void setUrl ( KUrl u
) { m_url
= u
; }
458 void setTitle( QString t
) { m_title
= t
; }
461 void paintCell( QPainter
*, const QColorGroup
&, int, int, int );
463 const KUrl
&url() const { return m_url
; }
464 const QString
&title() const { return m_title
; }
466 virtual QDomElement
xml() const;
468 virtual void updateInfo();
470 int rtti() const { return RTTI
; }
471 static const int RTTI
= 1003; //stream item
474 virtual void slotDoubleClicked();
475 virtual void showContextMenu( const QPoint
& );
482 class LastFmEntry
: public StreamEntry
486 LastFmEntry( Q3ListViewItem
*parent
, Q3ListViewItem
*after
, const KUrl
&u
, const QString
&t
)
487 : StreamEntry( parent
, after
, u
, t
) { }
488 LastFmEntry( Q3ListViewItem
*parent
, Q3ListViewItem
*after
, const QDomElement
&xmlDefinition
)
489 : StreamEntry( parent
, after
, xmlDefinition
) { }
490 virtual QDomElement
xml() const;
493 virtual void slotRenameItem() { /* Do nothing */ }
496 int rtti() const { return RTTI
; }
497 static const int RTTI
= 1008; //lastfm item
500 class StreamEditor
: public KDialog
503 StreamEditor( QWidget
*parent
, const QString
&title
, const QString
&url
, bool readonly
= false );
505 KUrl
url() const { return KUrl::KUrl( m_urlLineEdit
->text() ); }
506 QString
name() const { return m_nameLineEdit
->text().replace( "\n", " " ); }
509 KLineEdit
*m_urlLineEdit
;
510 KLineEdit
*m_nameLineEdit
;
514 class SmartPlaylist
: public PlaylistBrowserEntry
518 SmartPlaylist( Q3ListViewItem
*parent
, Q3ListViewItem
*after
, const QString
&name
, const QString
&query
);
519 SmartPlaylist( Q3ListViewItem
*parent
, Q3ListViewItem
*after
, const QString
&name
,
520 const QString
&urls
, const QString
&tags
);
521 SmartPlaylist( Q3ListViewItem
*parent
, Q3ListViewItem
*after
, const QDomElement
&xmlDefinition
);
523 bool isDynamic() const { return m_dynamic
; }
524 bool isEditable() const { return !m_xml
.isNull(); }
525 bool isTimeOrdered(); //returns yes if the ordering is based on a time attribute
527 QString
title() const { return m_title
; }
528 virtual QDomElement
xml() const { return m_xml
; }
531 void setDynamic( bool );
532 void setXml( const QDomElement
&xml
);
534 int rtti() const { return RTTI
; }
535 static const int RTTI
= 1004; //smart playlist item
538 virtual void slotDoubleClicked();
539 virtual void slotPostRenameItem( const QString newName
);
540 virtual void showContextMenu( const QPoint
& );
543 // for xml playlists, this member is computed on demand
544 QString m_sqlForTags
;
548 Q3ListViewItem
*m_after
;
551 // Build the query for a given xml object. If \p for expand is true,
552 // insert (*ExpandString*) as placeholders for childrens' filters
553 static QString
xmlToQuery( const QDomElement
&xml
, bool forExpand
= false );
556 //this class is used to store information of a playlist track
560 TrackItemInfo( const MetaBundle
&mb
);
562 const KUrl
&url() const { return m_url
; }
563 const QString
&album() const { return m_album
; }
564 const QString
&artist() const { return m_artist
; }
565 const QString
&title() const { return m_title
; }
566 const int length() const { return m_length
; }
577 @brief Implement a shoutcast playlist category
579 On open, download the shoutcast genre XML file.
581 Process the file and add each genre as a ShoutcastGenre
582 style PlaylistCategory
584 class ShoutcastBrowser
: public PlaylistCategory
588 ShoutcastBrowser( PlaylistCategory
* parent
);
589 void setOpen( bool open
);
592 virtual void slotDoubleClicked();
595 void doneGenreDownload( KIO::Job
*job
, const KUrl
&from
, const KUrl
&to
, time_t mtime
, bool directory
, bool renamed
);
596 void jobFinished( KJob
*job
);
597 void slotAnimation();
602 QPixmap
*m_loading1
, *m_loading2
; //icons for loading animation
603 QTimer m_animationTimer
;
607 @brief Implement a shoutcast genre category
609 On open, download the shoutcast station list XML file.
611 Process the file and add each station as a StreamEntry
613 class ShoutcastGenre
: public PlaylistCategory
617 ShoutcastGenre( ShoutcastBrowser
*browser
, Q3ListViewItem
*after
, QString genre
);
618 void setOpen( bool open
);
619 void appendAlternateGenre( QString alternateGenre
) { m_alternateGenres
<< alternateGenre
; }
622 virtual void slotDoubleClicked();
625 void doneListDownload( KIO::Job
*job
, const KUrl
&from
, const KUrl
&to
, time_t mtime
, bool directory
, bool renamed
);
626 void jobFinished( KJob
*job
);
627 void slotAnimation();
630 void startGenreDownload( QString genre
, QString tmppath
);
633 QPixmap
*m_loading1
, *m_loading2
; //icons for loading animation
634 QTimer m_animationTimer
;
635 QStringList m_alternateGenres
;
636 QStringList m_stations
;