Temporarily disable showing the mediabrowser as jefferais commit caused Amarok to...
[amarok.git] / src / playlist.h
blob606f36fed658c11ec093d71df449ce0dc4dd6f8b
1 /***************************************************************************
2 Playlist.h - description
3 -------------------
4 begin : Don Dez 5 2002
5 copyright : (C) 2002 by Mark Kretschmann
6 (C) 2005 Ian Monroe
7 (C) 2005 by Gábor Lehel
8 ***************************************************************************/
10 /***************************************************************************
11 * *
12 * This program is free software; you can redistribute it and/or modify *
13 * it under the terms of the GNU General Public License as published by *
14 * the Free Software Foundation; either version 2 of the License, or *
15 * (at your option) any later version. *
16 * *
17 ***************************************************************************/
19 #ifndef AMAROK_PLAYLIST_H
20 #define AMAROK_PLAYLIST_H
22 #include "config-amarok.h"
23 #include "amarok_export.h"
24 #include "amarokconfig.h"
25 #include "engineobserver.h" //baseclass
26 #include "dynamicmode.h"
27 #include "MainWindow.h" //friend
28 #include "playlistitem.h"
29 #include "metabundle.h"
30 #include "tooltip.h" //baseclass
31 #include "tracktooltip.h"
33 #include <k3listview.h> //baseclass
34 #include <kurl.h> //KUrl::List
35 #include <QDir> //stack allocated
36 #include <qpoint.h> //stack allocated
37 #include <q3ptrlist.h> //stack allocated
38 #include <QStringList> //stack allocated
39 //Added by qt3to4:
40 #include <QDragLeaveEvent>
41 #include <Q3ValueList>
42 #include <QLabel>
43 #include <QDragEnterEvent>
44 #include <QDragMoveEvent>
45 #include <QDropEvent>
46 #include <QResizeEvent>
47 #include <QMouseEvent>
48 #include <QEvent>
49 #include <QPaintEvent>
50 #include <QWheelEvent>
51 #include <vector> //stack allocated
53 class KAction;
54 class MyAtomicString;
55 class PlaylistItem;
56 class PlaylistAlbum;
57 class TagWriter;
58 class QLabel;
59 class QTimer;
62 /**
63 * @authors Mark Kretschmann && Max Howell
65 * Playlist inherits K3ListView privately and thus is no longer a ListView
66 * Instead it is a part of MainWindow and they interact in harmony. The change
67 * was necessary as it is too dangerous to allow public access to PlaylistItems
68 * due to the multi-threading environment.
70 * Unfortunately, since QObject is now inaccessible you have to connect slots
71 * via one of MainWindow's friend members or in Playlist
73 * If you want to add new playlist type functionality you should implement it
74 * inside this class or inside MainWindow.
79 class Playlist : private K3ListView, public EngineObserver, public Amarok::ToolTipClient
81 Q_OBJECT
83 public:
84 ~Playlist();
86 AMAROK_EXPORT static Playlist *instance() { return s_instance; }
87 static QString defaultPlaylistPath();
88 static const int NO_SORT = 200;
90 static const int Append = 1; /// inserts media after the last item in the playlist
91 static const int Queue = 2; /// inserts media after the currentTrack
92 static const int Clear = 4; /// clears the playlist first
93 static const int Replace = Clear;
94 static const int DirectPlay = 8; /// start playback of the first item in the list
95 static const int Unique = 16; /// don't insert anything already in the playlist
96 static const int StartPlay = 32; /// start playback of the first item in the list if nothing else playing
97 static const int Colorize = 64; /// colorize newly added items
98 static const int DefaultOptions = Append | Unique | StartPlay;
100 // it's really just the *ListView parts we want to hide...
101 Q3ScrollView *qscrollview() const
103 return reinterpret_cast<Q3ScrollView*>( const_cast<Playlist*>( this ) );
106 /** Add media to the playlist
107 * @param options you can OR these together, see the enum
108 * @param sql Sql program to execute */
109 AMAROK_EXPORT void insertMedia( KUrl::List, int options = Append );
110 void insertMediaSql( const QString& sql, int options = Append );
112 // Dynamic mode functions
113 void addDynamicModeTracks( uint songCount );
114 void adjustDynamicUpcoming( bool saveUndo = false );
115 void adjustDynamicPrevious( uint songCount, bool saveUndo = false );
116 void advanceDynamicTrack();
117 void setDynamicHistory( bool enable = true );
119 void burnPlaylist ( int projectType = -1 );
120 void burnSelectedTracks( int projectType = -1 );
121 int currentTrackIndex( bool onlyCountVisible = true );
122 bool isEmpty() const { return childCount() == 0; }
123 AMAROK_EXPORT bool isTrackBefore() const;
124 AMAROK_EXPORT bool isTrackAfter() const;
125 void restoreSession(); // called during initialisation
126 void setPlaylistName( const QString &name, bool proposeOverwriting = false ) { m_playlistName = name; m_proposeOverwriting = proposeOverwriting; }
127 void proposePlaylistName( const QString &name, bool proposeOverwriting = false ) { if( isEmpty() || m_playlistName==i18n("Untitled") ) m_playlistName = name; m_proposeOverwriting = proposeOverwriting; }
128 const QString &playlistName() const { return m_playlistName; }
129 bool proposeOverwriteOnSave() const { return m_proposeOverwriting; }
130 bool saveM3U( const QString&, bool relative = AmarokConfig::relativePlaylist() ) const;
131 void saveXML( const QString& );
132 int totalTrackCount() const;
133 BundleList nextTracks() const;
134 uint repeatAlbumTrackCount() const; //returns number of tracks from same album
135 //as current track that are in playlist (may require Play Albums in Order on).
136 //If the information is not available, returns 0.
138 //const so you don't change it behind Playlist's back, use modifyDynamicMode() for that
139 const DynamicMode *dynamicMode() const;
141 //modify the returned DynamicMode, then finishedModifying() it when done
142 DynamicMode *modifyDynamicMode();
144 //call this every time you modifyDynamicMode(), otherwise you'll get memory leaks and/or crashes
145 void finishedModifying( DynamicMode *mode );
147 int stopAfterMode();
149 void addCustomMenuItem ( const QString &submenu, const QString &itemTitle );
150 void customMenuClicked ( int id );
151 bool removeCustomMenuItem( const QString &submenu, const QString &itemTitle );
153 void setFont( const QFont &f ) { K3ListView::setFont( f ); } //made public for convenience
154 void unsetFont() { K3ListView::setFont(QFont()); }
156 PlaylistItem *firstChild() const { return static_cast<PlaylistItem*>( K3ListView::firstChild() ); }
157 PlaylistItem *lastItem() const { return static_cast<PlaylistItem*>( K3ListView::lastItem() ); }
158 PlaylistItem *currentItem() const { return static_cast<PlaylistItem*>( K3ListView::currentItem() ); }
160 int numVisibleColumns() const;
161 Q3ValueList<int> visibleColumns() const;
162 MetaBundle::ColumnMask getVisibleColumnMask() const;
163 int mapToLogicalColumn( int physical ) const; // Converts physical PlaylistItem column position to logical
164 QString columnText( int c ) const { return K3ListView::columnText( c ); }
165 void setColumns( Q3ValueList<int> order, Q3ValueList<int> visible );
167 /** Call this to prevent items being removed from the playlist, it is mostly for internal use only
168 * Don't forget to unlock() !! */
169 void lock();
170 void unlock();
172 //reimplemented to save columns by name instead of index, to be more resilient to reorderings and such
173 void saveLayout(KSharedConfigPtr config, const QString &group) const;
174 void restoreLayout(KSharedConfigPtr config, const QString &group);
176 //AFT-related functions
177 bool checkFileStatus( PlaylistItem * item );
178 void addToUniqueMap( const QString uniqueid, PlaylistItem* item );
179 void removeFromUniqueMap( const QString uniqueid, PlaylistItem* item );
181 enum RequestType { Prev = -1, Current = 0, Next = 1 };
182 enum StopAfterMode { DoNotStop, StopAfterCurrent, StopAfterQueue, StopAfterOther };
184 class Q3DragObject *dragObject();
185 friend class PlaylistItem;
186 friend class UrlLoader;
187 friend class QueueManager;
188 friend class QueueLabel;
189 friend class MainWindow;
190 friend class ColumnList;
191 // friend void Amarok::DcopPlaylistHandler::removeCurrentTrack(); //calls removeItem() and currentTrack()
192 // friend void Amarok::DcopPlaylistHandler::removeByIndex( int ); //calls removeItem()
193 friend class TagWriter; //calls removeItem()
194 friend void MainWindow::init(); //setting up connections etc.
195 friend TrackToolTip::TrackToolTip();
196 friend bool MainWindow::eventFilter( QObject*, QEvent* ); //for convenience we handle some playlist events here
198 public:
199 QPair<QString, QRect> toolTipText( QWidget*, const QPoint &pos ) const;
201 signals:
202 void aboutToClear();
203 void itemCountChanged( int newCount, int newLength, int visCount, int visLength, int selCount, int selLength );
204 void queueChanged( const QList<PlaylistItem*> &queued, const QList<PlaylistItem*> &dequeued );
205 void columnsChanged();
206 void dynamicModeChanged( const DynamicMode *newMode );
208 public slots:
209 void activateByIndex(int);
210 void addCustomColumn();
211 void appendMedia( const KUrl &url );
212 void appendMedia( const QString &path );
213 void clear();
214 void copyToClipboard( const Q3ListViewItem* = 0 ) const;
215 void deleteSelectedFiles();
216 void ensureItemCentered( Q3ListViewItem* item );
217 void playCurrentTrack();
218 void playNextTrack( const bool forceNext = true );
219 void playPrevTrack();
220 void queueSelected();
221 void setSelectedRatings( int rating );
222 void redo();
223 void removeDuplicates();
224 void removeSelectedItems();
225 void setDynamicMode( DynamicMode *mode );
226 void loadDynamicMode( DynamicMode *mode ); //saveUndoState() + setDynamicMode()
227 void disableDynamicMode();
228 void editActiveDynamicMode();
229 void rebuildDynamicModeCache();
230 void repopulate();
231 void scoreChanged( const QString &path, float score );
232 void ratingChanged( const QString &path, int rating );
233 void fileMoved( const QString &srcPath, const QString &dstPath );
234 void selectAll() { Q3ListView::selectAll( true ); }
235 void setFilter( const QString &filter );
236 void setFilterSlot( const QString &filter ); //uses a delay where applicable
237 void setStopAfterCurrent( bool on );
238 void setStopAfterItem( PlaylistItem *item );
239 void toggleStopAfterCurrentItem();
240 void toggleStopAfterCurrentTrack();
241 void setStopAfterMode( int mode );
242 void showCurrentTrack() { ensureItemCentered( m_currentTrack ); }
243 void showQueueManager();
244 void changeFromQueueManager( QList<PlaylistItem*> list );
245 void shuffle();
246 void undo();
247 void updateMetaData( const MetaBundle& );
248 void adjustColumn( int n );
249 void updateEntriesUrl( const QString &oldUrl, const QString &newUrl, const QString &uniqueid );
250 void updateEntriesUniqueId( const QString &url, const QString &oldid, const QString &newid );
251 void updateEntriesStatusDeleted( const QString &absPath, const QString &uniqueid );
252 void updateEntriesStatusAdded( const QString &absPath, const QString &uniqueid );
253 void updateEntriesStatusAdded( const QMap<QString,QString> &map );
255 protected:
256 virtual void fontChange( const QFont &old );
258 protected slots:
259 void contentsMouseMoveEvent( QMouseEvent *e = 0 );
260 void leaveEvent( QEvent *e );
261 void contentsMousePressEvent( QMouseEvent *e );
262 void contentsWheelEvent( QWheelEvent *e );
264 private slots:
265 void mediumChange( int );
266 void slotCountChanged();
267 void activate( Q3ListViewItem* );
268 void columnOrderChanged();
269 void columnResizeEvent( int, int, int );
270 void doubleClicked( Q3ListViewItem* );
272 void generateInfo(); //generates info for Random Albums
274 /* the only difference multi makes is whether it emits queueChanged(). (if multi, then no)
275 if you're queue()ing many items, consider passing true and emitting queueChanged() yourself. */
276 /* if invertQueue then queueing an already queued song dequeues it */
277 void queue( Q3ListViewItem*, bool multi = false, bool invertQueue = true );
279 void saveUndoState();
280 void setDelayedFilter(); //after the delay is over
281 void showContextMenu( Q3ListViewItem*, const QPoint&, int );
282 void slotEraseMarker();
283 void slotGlowTimer();
284 void reallyEnsureItemCentered();
285 void slotMouseButtonPressed( int, Q3ListViewItem*, const QPoint&, int );
286 void slotSingleClick();
287 void slotContentsMoving();
288 void slotRepeatTrackToggled( int mode );
289 void slotQueueChanged( const QList<PlaylistItem*> &in, const QList<PlaylistItem*> &out);
290 void slotUseScores( bool use );
291 void slotUseRatings( bool use );
292 void slotMoodbarPrefs( bool show, bool moodier, int alter, bool withMusic );
293 void updateNextPrev();
294 void writeTag( Q3ListViewItem*, const QString&, int );
296 private:
297 Playlist( QWidget* );
298 Playlist( const Playlist& ); //not defined
300 AMAROK_EXPORT static Playlist *s_instance;
302 void countChanged();
304 PlaylistItem *currentTrack() const { return m_currentTrack; }
305 PlaylistItem *restoreCurrentTrack();
307 void insertMediaInternal( const KUrl::List&, PlaylistItem*, int options = 0 );
308 bool isAdvancedQuery( const QString &query );
309 void refreshNextTracks( int = -1 );
310 void removeItem( PlaylistItem*, bool = false );
311 bool saveState( QStringList& );
312 void setCurrentTrack( PlaylistItem* );
313 void setCurrentTrackPixmap( int state = -1 );
314 void showTagDialog( QList<Q3ListViewItem*> items );
315 void sortQueuedItems();
316 void switchState( QStringList&, QStringList& );
317 void saveSelectedAsPlaylist();
318 void initStarPixmaps();
320 //engine observer functions
321 void engineNewMetaData( const MetaBundle&, bool );
322 void engineStateChanged( Engine::State, Engine::State = Engine::Empty );
324 /// K3ListView Overloaded functions
325 void contentsDropEvent ( QDropEvent* );
326 void contentsDragEnterEvent( QDragEnterEvent* );
327 void contentsDragMoveEvent ( QDragMoveEvent* );
328 void contentsDragLeaveEvent( QDragLeaveEvent* );
330 #ifdef PURIST //K3ListView imposes hand cursor so override it
331 void contentsMouseMoveEvent( QMouseEvent *e ) { Q3ListView::contentsMouseMoveEvent( e ); }
332 #endif
334 void customEvent( QEvent* );
335 bool eventFilter( QObject*, QEvent* );
336 void paletteChange( const QPalette& );
337 void rename( Q3ListViewItem*, int );
338 void setColumnWidth( int, int );
339 void setSorting( int, bool = true );
341 void viewportPaintEvent( QPaintEvent* );
342 void viewportResizeEvent( QResizeEvent* );
344 void appendToPreviousTracks( PlaylistItem *item );
345 void appendToPreviousAlbums( PlaylistAlbum *album );
346 void removeFromPreviousTracks( PlaylistItem *item = 0 );
347 void removeFromPreviousAlbums( PlaylistAlbum *album = 0 );
349 typedef QMap<MyAtomicString, PlaylistAlbum*> AlbumMap;
350 typedef QMap<MyAtomicString, AlbumMap> ArtistAlbumMap;
351 ArtistAlbumMap m_albums;
352 uint m_startupTime_t; //QDateTime::currentDateTime().toTime_t as of startup
353 uint m_oldestTime_t; //the createdate of the oldest song in the collection
356 /// ATTRIBUTES
358 PlaylistItem *m_currentTrack; //the track that is playing
359 Q3ListViewItem *m_marker; //track that has the drag/drop marker under it
360 PlaylistItem *m_hoveredRating; //if the mouse is hovering over the rating of an item
362 //NOTE these container types were carefully chosen
363 Q3PtrList<PlaylistAlbum> m_prevAlbums; //the previously played albums in Entire Albums mode
364 PLItemList m_prevTracks; //the previous history
365 QList<PlaylistItem*> m_nextTracks; //the tracks to be played after the current track
367 QString m_filter;
368 QString m_prevfilter;
369 QTimer *m_filtertimer;
371 PLItemList m_itemsToChangeTagsFor;
373 bool m_smartResizing;
375 int m_firstColumn;
376 int m_totalCount;
377 int m_totalLength;
378 int m_selCount;
379 int m_selLength;
380 int m_visCount;
381 int m_visLength;
382 qint64 m_total; //for Favor Tracks
383 bool m_itemCountDirty;
385 KAction *m_undoButton;
386 KAction *m_redoButton;
387 QAction *m_clearButton;
389 QDir m_undoDir;
390 QStringList m_undoList;
391 QStringList m_redoList;
392 uint m_undoCounter;
394 DynamicMode *m_dynamicMode;
395 KUrl::List m_queueList;
396 PlaylistItem *m_stopAfterTrack;
397 int m_stopAfterMode;
398 bool m_showHelp;
399 bool m_dynamicDirt; //So we don't call advanceDynamicTrack() on activate()
400 bool m_queueDirt; //When queuing disabled items, we need to place the marker on the newly inserted item
401 bool m_undoDirt; //Make sure we don't repopulate the playlist when dynamic mode and undo()
402 int m_insertFromADT; //Don't automatically start playing if a user hits Next in dynamic mode when not already playing
403 static QMutex *s_dynamicADTMutex;
405 Q3ListViewItem *m_itemToReallyCenter;
406 Q3ListViewItem *m_renameItem;
407 int m_renameColumn;
408 QTimer *m_clicktimer;
409 Q3ListViewItem *m_itemToRename;
410 QPoint m_clickPos;
411 int m_columnToRename;
413 QMap<QString, QStringList> m_customSubmenuItem;
414 QMap<int, QString> m_customIdItem;
416 bool isLocked() const { return m_lockStack > 0; }
418 /// stack counter for PLaylist::lock() and unlock()
419 int m_lockStack;
421 QString m_editOldTag; //text before inline editing ( the new tag is written only if it's changed )
423 std::vector<double> m_columnFraction;
425 QMap<QString,Q3PtrList<PlaylistItem>*> m_uniqueMap;
426 int m_oldRandom;
427 int m_oldRepeat;
429 QString m_playlistName;
430 bool m_proposeOverwriting;
433 class MyAtomicString: public AtomicString
435 public:
436 MyAtomicString() { }
437 MyAtomicString(const QString &string): AtomicString( string ) { }
438 MyAtomicString(const AtomicString &other): AtomicString( other ) { }
439 bool operator<(const AtomicString &other) const { return ptr() < other.ptr(); }
442 class PlaylistAlbum
444 public:
445 PLItemList tracks;
446 int refcount;
447 qint64 total; //for Favor Tracks
448 PlaylistAlbum(): refcount( 0 ), total( 0 ) { }
452 * Iterator class that only edits visible items! Preferentially always use
453 * this! Invisible items should not be operated on! To iterate over all
454 * items use MyIt::All as the flags parameter. MyIt::All cannot be OR'd,
455 * sorry.
458 class PlaylistIterator : public Q3ListViewItemIterator
460 public:
461 explicit PlaylistIterator( Q3ListViewItem *item, int flags = 0 )
462 //QListViewItemIterator is not great and doesn't allow you to see everything if you
463 //mask both Visible and Invisible :( instead just visible items are returned
464 : Q3ListViewItemIterator( item, flags == All ? 0 : flags | Visible )
467 explicit PlaylistIterator( Q3ListView *view, int flags = 0 )
468 : Q3ListViewItemIterator( view, flags == All ? 0 : flags | Visible )
471 //FIXME! Dirty hack for enabled/disabled items.
472 enum IteratorFlag {
473 Visible = Q3ListViewItemIterator::Visible,
474 All = Q3ListViewItemIterator::Invisible
477 inline PlaylistItem *operator*() { return static_cast<PlaylistItem*>( Q3ListViewItemIterator::operator*() ); }
479 /// @return the next visible PlaylistItem after item
480 static PlaylistItem *nextVisible( PlaylistItem *item )
482 PlaylistIterator it( item );
483 return (*it == item) ? *static_cast<PlaylistIterator&>(++it) : *it;
486 static PlaylistItem *prevVisible( PlaylistItem *item )
488 PlaylistIterator it( item );
489 return (*it == item) ? *static_cast<PlaylistIterator&>(--it) : *it;
494 #endif //AMAROK_PLAYLIST_H