Header cleanup
[amarok.git] / src / playlistbrowseritem.h
blob5e777f305960d01bdd32d0b78aa058acf429db05
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
18 #include <kio/job.h>
19 #include <klineedit.h>
20 #include <k3listview.h>
21 #include <kurl.h>
23 #include <qdom.h>
24 #include <QFile>
25 #include <q3http.h>
26 #include <q3ptrlist.h>
27 #include <QTimer> // Podcast loading animation
28 #include <q3url.h>
29 //Added by qt3to4:
30 #include <Q3ValueList>
31 #include <QCustomEvent>
32 #include <QPixmap>
34 class MetaBundle;
35 class PlaylistTrackItem;
36 class TrackItemInfo;
38 namespace KIO { class Job; class TransferJob; class CopyJob; } //podcast downloads
40 /**
41 * RTTI VALUES
42 * 1000 - PlaylistCategory
43 * 1001 - PlaylistEntry
44 * 1002 - PlaylistTrackItem
45 * 1003 - StreamEntry
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
56 Q_OBJECT
57 public:
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 ) {};
74 public slots:
75 virtual void slotDoubleClicked();
76 virtual void slotRenameItem();
77 virtual void slotPostRenameItem( const QString newName );
78 virtual void showContextMenu( const QPoint & ) {};
80 protected:
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;
86 private:
87 bool m_kept;
90 class DynamicEntry : public PlaylistBrowserEntry, public DynamicMode
92 Q_OBJECT
93 public:
94 DynamicEntry( Q3ListViewItem *parent, Q3ListViewItem *after, const QString &title );
95 DynamicEntry( Q3ListViewItem *parent, Q3ListViewItem *after, const QDomElement &xmlDefinition );
96 ~DynamicEntry() { };
98 virtual QString text( int column ) const;
100 virtual QDomElement xml() const;
102 static const int RTTI = 1005;
103 int rtti() const { return RTTI; }
105 public slots:
106 virtual void slotDoubleClicked();
107 virtual void showContextMenu( const QPoint & );
110 class PlaylistCategory : public PlaylistBrowserEntry
112 Q_OBJECT
113 public:
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
135 public slots:
136 virtual void slotDoubleClicked();
137 virtual void slotRenameItem();
138 virtual void showContextMenu( const QPoint & );
140 protected:
141 void okRename( int col );
143 private:
145 void setXml( const QDomElement &xml );
147 QString m_title;
148 int m_id;
149 bool m_folder;
153 class PlaylistEntry : public PlaylistBrowserEntry
155 Q_OBJECT
157 friend class PlaylistTrackItem;
158 friend class TrackItemInfo;
159 friend class PlaylistCategory;
161 public:
162 PlaylistEntry( Q3ListViewItem *parent, Q3ListViewItem *after, const KUrl &, int tracks=0, int length=0 );
163 PlaylistEntry( Q3ListViewItem *parent, Q3ListViewItem *after, const QDomElement &xmlDefinition );
164 ~PlaylistEntry();
166 void sortChildItems ( int /*column*/, bool /*ascending*/ ) { /* Don't sort its children */ }; //reimplemented
168 void load();
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 );
192 void setup();
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
203 public slots:
204 virtual void slotDoubleClicked();
205 virtual void slotPostRenameItem( const QString newName );
206 virtual void showContextMenu( const QPoint & );
208 signals:
209 void startingLoading();
210 void loaded();
212 private slots:
213 void slotAnimation();
215 private:
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
225 bool m_loading;
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;
230 uint m_iconCounter;
231 PlaylistTrackItem *m_lastTrack;
234 class PlaylistTrackItem : public PlaylistBrowserEntry
236 Q_OBJECT
237 friend class TrackItemInfo;
239 public:
240 PlaylistTrackItem( Q3ListViewItem *parent, Q3ListViewItem *after, TrackItemInfo *info );
242 const KUrl &url();
243 TrackItemInfo *trackInfo() const { return m_trackInfo; }
245 int rtti() const { return RTTI; }
246 static const int RTTI = 1002; //track item
248 public slots:
249 virtual void slotDoubleClicked();
250 virtual void slotRenameItem() { /* Do nothing */ };
251 virtual void showContextMenu( const QPoint & );
253 private:
254 TrackItemInfo *m_trackInfo;
257 /// Stored in the database
258 class PodcastEpisode : public PlaylistBrowserEntry
260 Q_OBJECT
262 public:
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 ); }
277 // for convenience
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 );
291 void setup();
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 );
302 signals:
303 void downloadFinished();
304 void downloadAborted();
306 public slots:
307 const bool isOnDisk();
308 virtual void slotDoubleClicked();
309 virtual void slotRenameItem() { /* Do nothing */ };
310 virtual void showContextMenu( const QPoint & );
312 private slots:
313 void abortDownload();
314 void downloadResult( KJob * transferJob );
315 void slotAnimation();
316 void redirected( KIO::Job * job,const KUrl & redirectedUrl );
318 private:
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();
327 void updatePixmap();
329 Q3ListViewItem *m_parent; //podcast channel it belongs to
330 PodcastEpisodeBundle m_bundle;
331 KUrl m_localUrl;
333 bool m_fetching;
334 QTimer m_animationTimer;
335 uint m_iconCounter;
337 KIO::StoredTransferJob* m_podcastEpisodeJob;
338 QString m_filename;
340 bool m_downloaded; //marked as downloaded in cached xml
341 bool m_onDisk;
344 /// Stored in the database
345 class PodcastChannel : public PlaylistBrowserEntry
347 Q_OBJECT
349 public:
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
368 void load();
369 const bool isPolished() const { return m_polished; }
371 void configure();
372 void fetch();
373 void rescan();
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
403 public slots:
404 virtual void slotDoubleClicked();
405 virtual void slotRenameItem() { /* Do nothing */ };
406 virtual void showContextMenu( const QPoint & );
408 private slots:
409 void abortFetch();
410 void downloadChildQueue();
411 void fetchResult( KIO::Job* job );
412 void slotAnimation();
414 private:
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 );
421 void purge();
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.
432 bool m_polished;
434 KUrl m_url; //remote xml url
435 bool m_fetching;
436 bool m_updating;
437 QTimer m_animationTimer;
438 uint m_iconCounter;
439 bool m_new;
440 bool m_hasProblem;
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
451 Q_OBJECT
452 public:
453 StreamEntry( Q3ListViewItem *parent, Q3ListViewItem *after, const KUrl &, const QString &t );
454 StreamEntry( Q3ListViewItem *parent, Q3ListViewItem *after, const QDomElement &xmlDefinition );
455 ~StreamEntry() { };
457 void setUrl ( KUrl u ) { m_url = u; }
458 void setTitle( QString t ) { m_title = t; }
460 void setup();
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
473 public slots:
474 virtual void slotDoubleClicked();
475 virtual void showContextMenu( const QPoint & );
477 protected:
478 QString m_title;
479 KUrl m_url;
482 class LastFmEntry : public StreamEntry
484 Q_OBJECT
485 public:
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;
492 public slots:
493 virtual void slotRenameItem() { /* Do nothing */ }
495 public:
496 int rtti() const { return RTTI; }
497 static const int RTTI = 1008; //lastfm item
500 class StreamEditor : public KDialog
502 public:
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", " " ); }
508 private:
509 KLineEdit *m_urlLineEdit;
510 KLineEdit *m_nameLineEdit;
514 class SmartPlaylist : public PlaylistBrowserEntry
516 Q_OBJECT
517 public:
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
526 QString query();
527 QString title() const { return m_title; }
528 virtual QDomElement xml() const { return m_xml; }
530 int length();
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
537 public slots:
538 virtual void slotDoubleClicked();
539 virtual void slotPostRenameItem( const QString newName );
540 virtual void showContextMenu( const QPoint & );
542 private:
543 // for xml playlists, this member is computed on demand
544 QString m_sqlForTags;
546 QString m_title;
547 QDomElement m_xml;
548 Q3ListViewItem *m_after;
549 bool m_dynamic;
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
557 class TrackItemInfo
559 public:
560 TrackItemInfo( const MetaBundle &mb );
561 ~TrackItemInfo() {}
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; }
568 private:
569 KUrl m_url;
570 QString m_artist;
571 QString m_album;
572 QString m_title;
573 int 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
586 Q_OBJECT
587 public:
588 ShoutcastBrowser( PlaylistCategory* parent );
589 void setOpen( bool open );
591 public slots:
592 virtual void slotDoubleClicked();
594 private slots:
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();
599 private:
600 bool m_downloading;
601 KIO::CopyJob *m_cj;
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
615 Q_OBJECT
616 public:
617 ShoutcastGenre( ShoutcastBrowser *browser, Q3ListViewItem *after, QString genre );
618 void setOpen( bool open );
619 void appendAlternateGenre( QString alternateGenre ) { m_alternateGenres << alternateGenre; }
621 public slots:
622 virtual void slotDoubleClicked();
624 private slots:
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();
629 private:
630 void startGenreDownload( QString genre, QString tmppath );
631 bool m_downloading;
632 QString m_genre;
633 QPixmap *m_loading1, *m_loading2; //icons for loading animation
634 QTimer m_animationTimer;
635 QStringList m_alternateGenres;
636 QStringList m_stations;
637 int m_totalJobs;
638 int m_completedJobs;
641 #endif