File indexing completed on 2021-12-21 13:27:57

0001 /**
0002  * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
0003  * Copyright (C) 2007 Michael Pyne <mpyne@kde.org>
0004  *
0005  * This program is free software; you can redistribute it and/or modify it under
0006  * the terms of the GNU General Public License as published by the Free Software
0007  * Foundation; either version 2 of the License, or (at your option) any later
0008  * version.
0009  *
0010  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0011  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0012  * PARTICULAR PURPOSE. See the GNU General Public License for more details.
0013  *
0014  * You should have received a copy of the GNU General Public License along with
0015  * this program.  If not, see <http://www.gnu.org/licenses/>.
0016  */
0017 
0018 #ifndef JUK_PLAYLIST_H
0019 #define JUK_PLAYLIST_H
0020 
0021 #include <QVector>
0022 #include <QEvent>
0023 #include <QList>
0024 #include <QTreeWidget>
0025 #include <QFuture>
0026 
0027 #include "covermanager.h"
0028 #include "stringhash.h"
0029 #include "playlistsearch.h"
0030 #include "tagguesser.h"
0031 #include "playlistinterface.h"
0032 #include "filehandle.h"
0033 #include "juk_debug.h"
0034 
0035 class KActionMenu;
0036 
0037 class QAction;
0038 class QFileInfo;
0039 class QMimeData;
0040 class QTimer;
0041 
0042 class WebImageFetcher;
0043 class PlaylistItem;
0044 class PlaylistCollection;
0045 class CollectionListItem;
0046 
0047 typedef QVector<PlaylistItem *> PlaylistItemList;
0048 
0049 class Playlist : public QTreeWidget, public PlaylistInterface
0050 {
0051     Q_OBJECT
0052 
0053 public:
0054 
0055     explicit Playlist(PlaylistCollection *collection, const QString &name = QString(),
0056              const QString &iconName = "audio-midi");
0057     Playlist(PlaylistCollection *collection, const PlaylistItemList &items,
0058              const QString &name = QString(), const QString &iconName = "audio-midi");
0059     Playlist(PlaylistCollection *collection, const QFileInfo &playlistFile,
0060              const QString &iconName = "audio-midi");
0061 
0062     /**
0063      * This constructor should generally only be used either by the cache
0064      * restoration methods or by subclasses that want to handle calls to
0065      * PlaylistCollection::setupPlaylist() differently.
0066      *
0067      * @param extraColumns is used to preallocate columns for subclasses that
0068      * need them (since extra columns are assumed to start from 0). extraColumns
0069      * should be equal to columnOffset() (we can't use columnOffset until the
0070      * ctor has run).
0071      */
0072     Playlist(PlaylistCollection *collection, bool delaySetup, int extraColumns = 0);
0073 
0074     virtual ~Playlist();
0075 
0076 
0077     // The following group of functions implement the PlaylistInterface API.
0078 
0079     virtual QString name() const override;
0080     virtual FileHandle currentFile() const override;
0081     virtual int count() const override { return model()->rowCount(); }
0082     virtual int time() const override { return m_time; }
0083     virtual void playNext() override;
0084     virtual void playPrevious() override;
0085     virtual void stop() override;
0086 
0087     /**
0088      * Plays the top item of the playlist.
0089      */
0090     void playFirst();
0091 
0092     /**
0093      * Plays the next album in the playlist.  Only useful when in album random
0094      * play mode.
0095      */
0096     void playNextAlbum();
0097 
0098     /**
0099      * Saves the file to the currently set file name.  If there is no filename
0100      * currently set, the default behavior is to prompt the user for a file
0101      * name.
0102      */
0103     virtual void save();
0104 
0105     /**
0106      * Standard "save as".  Prompts the user for a location where to save the
0107      * playlist to.
0108      */
0109     virtual void saveAs();
0110 
0111     /**
0112      * Removes \a item from the Playlist, but not from the disk.
0113      *
0114      * Since the GUI updates after an item is cleared, you should use clearItems() if you have
0115      * a list of items to remove, as that will remove the whole batch before updating
0116      * other components/GUI to the change.
0117      */
0118     virtual void clearItem(PlaylistItem *item);
0119 
0120     /**
0121      * Remove \a items from the playlist and emit a signal indicating
0122      * that the number of items in the list has changed.
0123      */
0124     virtual void clearItems(const PlaylistItemList &items);
0125 
0126     /**
0127      * Accessor function to return a pointer to the currently playing file.
0128      *
0129      * @return 0 if no file is playing, otherwise a pointer to the PlaylistItem
0130      *     of the track that is currently playing.
0131      */
0132     static PlaylistItem *playingItem();
0133 
0134     /**
0135      * All of the (media) files in the list.
0136      */
0137     QStringList files() const;
0138 
0139     /**
0140      * Returns a list of all of the items in the playlist.
0141      */
0142     virtual PlaylistItemList items();
0143 
0144     /**
0145      * Returns a list of all of the \e visible items in the playlist.
0146      */
0147     PlaylistItemList visibleItems();
0148 
0149     /**
0150      * Returns a list of the currently selected items.
0151      */
0152     PlaylistItemList selectedItems();
0153 
0154     /**
0155      * Returns properly casted first child item in list.
0156      */
0157     PlaylistItem *firstChild() const;
0158 
0159     /**
0160      * Allow duplicate files in the playlist.
0161      */
0162     void setAllowDuplicates(bool allow) { m_allowDuplicates = allow; }
0163 
0164     /**
0165      * This is being used as a mini-factory of sorts to make the construction
0166      * of PlaylistItems virtual.  In this case it allows for the creation of
0167      * both PlaylistItems and CollectionListItems.
0168      */
0169     virtual PlaylistItem *createItem(const FileHandle &file,
0170                                      QTreeWidgetItem *after = nullptr);
0171 
0172     /**
0173      * This is implemented as a template method to allow subclasses to
0174      * instantiate their PlaylistItem subclasses using the same method.
0175      */
0176     template <class ItemType>
0177     ItemType *createItem(const FileHandle &file,
0178                          QTreeWidgetItem *after = nullptr);
0179 
0180     virtual void createItems(const PlaylistItemList &siblings, PlaylistItem *after = nullptr);
0181 
0182     /**
0183      * This handles adding files of various types -- music, playlist or directory
0184      * files.  Music files that are found will be added to this playlist.  New
0185      * playlist files that are found will result in new playlists being created.
0186      *
0187      * Note that this should not be used in the case of adding *only* playlist
0188      * items since it has the overhead of checking to see if the file is a playlist
0189      * or directory first.
0190      */
0191     virtual void addFiles(const QStringList &files, PlaylistItem *after = nullptr);
0192 
0193     /**
0194      * Returns the file name associated with this playlist (an m3u file) or
0195      * an empty QString if no such file exists.
0196      */
0197     QString fileName() const { return m_fileName; }
0198 
0199     /**
0200      * Sets the file name to be associated with this playlist; this file should
0201      * have the "m3u" extension.
0202      */
0203     void setFileName(const QString &n) { m_fileName = n; }
0204 
0205     /**
0206      * Hides column \a c.  If \a updateSearch is true then a signal that the
0207      * visible columns have changed will be emitted and things like the search
0208      * will be updated.
0209      */
0210     void hideColumn(int c, bool updateSearch = true);
0211 
0212     /**
0213      * Shows column \a c.  If \a updateSearch is true then a signal that the
0214      * visible columns have changed will be emitted and things like the search
0215      * will be updated.
0216      */
0217     void showColumn(int c, bool updateSearch = true);
0218 
0219     void sortByColumn(int column, Qt::SortOrder order = Qt::AscendingOrder);
0220 
0221     /**
0222      * This sets a name for the playlist that is \e different from the file name.
0223      */
0224     void setName(const QString &n);
0225 
0226     /**
0227      * Returns the KActionMenu that allows this to be embedded in menus outside
0228      * of the playlist.
0229      */
0230     KActionMenu *columnVisibleAction() const { return m_columnVisibleAction; }
0231 
0232     /**
0233      * Set item to be the playing item.  If \a item is null then this will clear
0234      * the playing indicator.
0235      */
0236     void setPlaying(PlaylistItem *item, bool addToHistory = true);
0237 
0238     /**
0239      * Returns true if this playlist is currently playing.
0240      */
0241     bool playing() const override;
0242 
0243     /**
0244      * This forces an update of the left most visible column, but does not save
0245      * the settings for this.
0246      */
0247     void updateLeftColumn();
0248 
0249     /**
0250      * Returns the leftmost visible column of the listview.
0251      */
0252     int leftColumn() const { return m_leftColumn; }
0253 
0254     /**
0255      * Sets the items in the list to be either visible based on the value of
0256      * visible.  This is useful for search operations and such.
0257      */
0258     void setItemsVisible(const QModelIndexList &indexes, bool visible = true);
0259 
0260     /**
0261      * Returns the search associated with this list, or an empty search if one
0262      * has not yet been set.
0263      */
0264     PlaylistSearch* search() const { return m_search; }
0265 
0266     /**
0267      * Set the search associated with this playlist.
0268      */
0269     void setSearch(PlaylistSearch* s);
0270 
0271     /**
0272      * If the search is disabled then all items will be shown, not just those that
0273      * match the current search.
0274      */
0275     void setSearchEnabled(bool searchEnabled);
0276 
0277     /**
0278      * Subclasses of Playlist which add new columns will set this value to
0279      * specify how many of those columns exist.  This allows the Playlist
0280      * class to do some internal calculations on the number and positions
0281      * of columns.
0282      */
0283     virtual int columnOffset() const { return 0; }
0284 
0285     /**
0286      * Some subclasses of Playlist will be "read only" lists (i.e. the history
0287      * playlist).  This is a way for those subclasses to indicate that to the
0288      * Playlist internals.
0289      */
0290     virtual bool readOnly() const { return false; }
0291 
0292     /**
0293      * Returns true if it's possible to reload this playlist.
0294      */
0295     virtual bool canReload() const { return !m_fileName.isEmpty(); }
0296 
0297     /**
0298      * Returns true if the playlist is a search playlist and the search should be
0299      * editable.
0300      */
0301     virtual bool searchIsEditable() const { return false; }
0302 
0303     /**
0304      * Synchronizes the playing item in this playlist with the playing item
0305      * in \a playlist.  If \a setMaster is true, this list will become the source
0306      * for determining the next item.
0307      */
0308     void synchronizePlayingItems(Playlist *playlist, bool setMaster);
0309 
0310     /**
0311      * Synchronizes the playing item in this playlist with the playing item
0312      * in \a sources.  If \a setMaster is true, this list will become the source
0313      * for determining the next item.
0314      */
0315     void synchronizePlayingItems(const PlaylistList &sources, bool setMaster);
0316 
0317     /**
0318      * Playlists have a common set of shared settings such as visible columns
0319      * that should be applied just before the playlist is shown.  Calling this
0320      * method applies those.
0321      */
0322     void applySharedSettings();
0323 
0324     void read(QDataStream &s);
0325 
0326     static void setShuttingDown() { m_shuttingDown = true; }
0327 
0328     void playlistItemsChanged() override;
0329 
0330 public slots:
0331     /**
0332      * Remove the currently selected items from the playlist and disk.
0333      */
0334     void slotRemoveSelectedItems() { removeFromDisk(selectedItems()); }
0335 
0336     /*
0337      * The edit slots are required to use the canonical names so that they are
0338      * detected by the application wide framework.
0339      */
0340     virtual void cut() { copy(); clear(); }
0341 
0342     /**
0343      * Puts a list of URLs pointing to the files in the current selection on the
0344      * clipboard.
0345      */
0346     virtual void copy();
0347 
0348     /**
0349      * Checks the clipboard for local URLs to be inserted into this playlist.
0350      */
0351     virtual void paste();
0352 
0353     /**
0354      * Removes the selected items from the list, but not the disk.
0355      *
0356      * @see clearItem()
0357      * @see clearItems()
0358      */
0359     virtual void clear();
0360 
0361     /**
0362      * Refreshes the tags of the selection from disk, or all of the files in the
0363      * list if there is no selection.
0364      */
0365     virtual void slotRefresh();
0366 
0367     /**
0368      * Opens the containing folder of the selected files.
0369      */
0370     virtual void slotOpenItemDir();
0371 
0372     void slotGuessTagInfo(TagGuesser::Type type);
0373 
0374     /**
0375      * Renames the selected items' files based on their tags contents.
0376      *
0377      * @see PlaylistItem::renameFile()
0378      */
0379     void slotRenameFile();
0380 
0381     /**
0382      * Select a track to play after being stopped.
0383      *
0384      * @see playNext()
0385      */
0386     void slotBeginPlayback();
0387 
0388     /**
0389      * Sets the cover of the selected items, pass in true if you want to load from the local system,
0390      * false if you want to load from the internet.
0391      */
0392     void slotAddCover(bool fromLocal);
0393 
0394     /**
0395      * Shows a large image of the cover
0396      */
0397     void slotViewCover();
0398 
0399     /**
0400      * Removes covers from the selected items
0401      */
0402     void slotRemoveCover();
0403 
0404     /**
0405      * Shows the cover manager GUI dialog
0406      */
0407     void slotShowCoverManager();
0408 
0409     /**
0410      * Reload the playlist contents from the m3u file.
0411      */
0412     virtual void slotReload();
0413 
0414     /**
0415      * Ensures the random sequence of playlist items is built. Ignored if we're
0416      * not in random playback mode so it is safe to call in any mode.
0417      */
0418     void refillRandomList();
0419 
0420     /**
0421      * Tells the listview that the next time that it paints that the weighted
0422      * column widths must be recalculated.  If this is called without a column
0423      * all visible columns are marked as dirty.
0424      */
0425     void slotWeightDirty(int column = -1);
0426 
0427     void slotShowPlaying();
0428 
0429     void slotColumnResizeModeChanged();
0430 
0431 protected:
0432     /**
0433      * Remove \a items from the playlist and disk.  This will ignore items that
0434      * are not actually in the list.
0435      */
0436     void removeFromDisk(const PlaylistItemList &items);
0437 
0438     /**
0439      * Adds and removes items from this Playlist as necessary to ensure that
0440      * the same items are present in this Playlist as in @p itemList.
0441      *
0442      * No ordering guarantees are imposed, just that the playlist will have the
0443      * same items as in the given list afterwards.
0444      */
0445     void synchronizeItemsTo(const PlaylistItemList &itemList);
0446 
0447     /**
0448      * Completes the actions with the parent PlaylistCollection needed to
0449      * actually start playing back the given PlaylistItem.
0450      */
0451     virtual void beginPlayingItem(PlaylistItem *itemToPlay);
0452 
0453     // the following are all reimplemented from base classes
0454 
0455     virtual bool eventFilter(QObject *watched, QEvent *e) override;
0456     virtual void keyPressEvent(QKeyEvent *e) override;
0457     QStringList mimeTypes() const override;
0458 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0459     QMimeData* mimeData(const QList<QTreeWidgetItem *> items) const override;
0460 #else
0461     QMimeData* mimeData(const QList<QTreeWidgetItem *> &items) const override;
0462 #endif
0463     virtual bool dropMimeData(QTreeWidgetItem *parent, int index, const QMimeData *data, Qt::DropAction action) override;
0464     virtual void dropEvent(QDropEvent *e) override;
0465     virtual void dragEnterEvent(QDragEnterEvent *e) override;
0466     virtual void showEvent(QShowEvent *e) override;
0467     virtual void paintEvent(QPaintEvent *pe) override;
0468     virtual void resizeEvent(QResizeEvent *re) override;
0469 
0470     virtual void drawRow(QPainter *p, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
0471 
0472     virtual void insertItem(QTreeWidgetItem *item);
0473     virtual void takeItem(QTreeWidgetItem *item);
0474 
0475     virtual bool hasItem(const QString &file) const { return m_members.contains(file); }
0476 
0477     /**
0478      * Do some final initialization of created items.  Notably ensure that they
0479      * are shown or hidden based on the contents of the current PlaylistSearch.
0480      *
0481      * This is called by the PlaylistItem constructor.
0482      */
0483     void setupItem(PlaylistItem *item);
0484 
0485     /**
0486      * Forwards the call to the parent to enable or disable automatic deletion
0487      * of tree view playlists.  Used by CollectionListItem.
0488      */
0489     void setDynamicListsFrozen(bool frozen);
0490 
0491     template <class ItemType, class SiblingType>
0492     ItemType *createItem(SiblingType *sibling, ItemType *after = nullptr);
0493 
0494     /**
0495      * As a template this allows us to use the same code to initialize the items
0496      * in subclasses. ItemType should be a PlaylistItem subclass.
0497      */
0498     template <template <typename> class Container, class ItemType, class SiblingType>
0499     void createItems(const Container<SiblingType *> &siblings, ItemType *after = nullptr);
0500 
0501 protected slots:
0502     void slotPopulateBackMenu() const;
0503     void slotPlayFromBackMenu(QAction *);
0504 
0505 signals:
0506 
0507     /**
0508      * This is connected to the PlaylistBox::Item to let it know when the
0509      * playlist's name has changed.
0510      */
0511     void signalNameChanged(const QString &name);
0512 
0513     /**
0514      * This signal is emitted just before a playlist item is removed from the
0515      * list allowing for any cleanup that needs to happen.  Typically this
0516      * is used to remove the item from the history and safeguard against
0517      * dangling pointers.
0518      */
0519     void signalAboutToRemove(PlaylistItem *item);
0520 
0521     void signalEnableDirWatch(bool enable);
0522 
0523     void signalPlaylistItemsDropped(Playlist *p);
0524 
0525     void signalMoveFocusAway();
0526 
0527 private:
0528     // Common constructor routines, inherited by other constructors
0529     Playlist(
0530             bool delaySetup, const QString &name,
0531             PlaylistCollection *collection, const QString &iconName,
0532             int extraCols);
0533 
0534     void setup(int numColumnsToReserve);
0535 
0536     /**
0537      * This function is called to let the user know that JuK has automatically enabled
0538      * manual column width adjust mode.
0539      */
0540     void notifyUserColumnWidthModeChanged();
0541 
0542     /**
0543      * Load the playlist from a file.  \a fileName should be the absolute path.
0544      * \a fileInfo should point to the same file as \a fileName.  This is a
0545      * little awkward API-wise, but keeps us from throwing away useful
0546      * information.
0547      */
0548     void loadFile(const QString &fileName, const QFileInfo &fileInfo);
0549 
0550     /**
0551      * Writes \a text to \a item in \a column.  This is used by the inline tag
0552      * editor.  Returns false if the tag update failed.
0553      */
0554     bool editTag(PlaylistItem *item, const QString &text, int column);
0555 
0556     /**
0557      * Returns the index of the left most visible column in the playlist.
0558      *
0559      * \see isColumnHidden()
0560      */
0561     int leftMostVisibleColumn() const;
0562 
0563     /// Creates the context menu on demand
0564     void createPlaylistRMBMenu();
0565 
0566     /**
0567      * This method is used internally to provide the backend to the other item
0568      * lists.
0569      *
0570      * \see items()
0571      * \see visibleItems()
0572      * \see selectedItems()
0573      */
0574     PlaylistItemList items(QTreeWidgetItemIterator::IteratorFlags flags);
0575 
0576     /**
0577      * Build the column "weights" for the weighted width mode.
0578      */
0579     void calculateColumnWeights();
0580 
0581     void addPlaylistFile(const QString &m3uFile);
0582     QFuture<void> addFilesFromDirectory(const QString &dirPath);
0583     QFuture<void> addUntypedFile(const QString &file, PlaylistItem *after = nullptr);
0584     void cleanupAfterAllFileLoadsCompleted();
0585     void addFilesFromMimeData(const QMimeData *urls, PlaylistItem *after = nullptr);
0586 
0587     void redisplaySearch() { setSearch(m_search); }
0588 
0589     /**
0590      * Sets the cover for items to the cover identified by id.
0591      */
0592     void refreshAlbums(const PlaylistItemList &items, coverKey id = CoverManager::NoMatch);
0593 
0594     void refreshAlbum(const QString &artist, const QString &album);
0595 
0596     void updatePlaying() const;
0597 
0598     /**
0599      * This function should be called when item is deleted to ensure that any
0600      * internal bookkeeping is performed.  It is automatically called by
0601      * PlaylistItem::~PlaylistItem and by clearItem() and clearItems().
0602      */
0603     void updateDeletedItem(PlaylistItem *item);
0604 
0605     /**
0606      * Used as a helper to implement template<> createItem().  This grabs the
0607      * CollectionListItem for file if it exists, otherwise it creates a new one and
0608      * returns that.  If nullptr is returned then some kind of error occurred,
0609      * and you should probably do nothing with the FileHandle you have.
0610      */
0611     CollectionListItem *collectionListItem(const FileHandle &file);
0612 
0613     /**
0614      * This class is used internally to store settings that are shared by all
0615      * of the playlists, such as column order.  It is implemented as a singleton.
0616      */
0617     class SharedSettings;
0618 
0619 private slots:
0620 
0621     /**
0622      * Handle the necessary tasks needed to create and setup the playlist that
0623      * don't need to happen in the ctor, such as setting up the columns,
0624      * initializing the RMB menu, and setting up signal/slot connections.
0625      *
0626      * Used to be a subclass of K3ListView::polish() but the timing of the
0627      * call is not consistent and therefore lead to crashes.
0628      */
0629     void slotInitialize(int numColumnsToReserve);
0630 
0631     void slotUpdateColumnWidths();
0632 
0633     void slotAddToUpcoming();
0634 
0635     /**
0636      * Show the RMB menu.  Matches the signature for the signal
0637      * QListView::contextMenuRequested().
0638      */
0639     void slotShowRMBMenu(const QPoint &point);
0640 
0641     /**
0642      * This slot is called when the inline tag editor has completed its editing
0643      * and starts the process of renaming the values.
0644      */
0645     void slotInlineEditDone(QTreeWidgetItem *, int column);
0646 
0647     /**
0648      * The image fetcher will update the cover asynchronously, this internal
0649      * slot is called when it happens.
0650      */
0651     void slotCoverChanged(int coverId);
0652 
0653     /**
0654      * Moves the column \a from to the position \a to.  This matches the signature
0655      * for the signal QHeader::indexChange().
0656      */
0657     void slotColumnOrderChanged(int, int from, int to);
0658 
0659     /**
0660      * Toggles a columns visible status.  Useful for KActions.
0661      *
0662      * \see hideColumn()
0663      * \see showColumn()
0664      */
0665     void slotToggleColumnVisible(QAction *action);
0666 
0667     /**
0668      * Prompts the user to create a new playlist with from the selected items.
0669      */
0670     void slotCreateGroup();
0671 
0672     /**
0673      * This slot is called when the user drags the slider in the listview header
0674      * to manually set the size of the column.
0675      */
0676     void columnResized(int column, int oldSize, int newSize);
0677 
0678     void slotPlayCurrent();
0679     void slotUpdateTime();
0680 
0681 private:
0682     friend class PlaylistItem;
0683 
0684     PlaylistCollection *m_collection = nullptr;
0685     StringHash m_members;
0686 
0687     // This is only defined if the playlist name is something other than the
0688     // file name.
0689     QString m_playlistName;
0690     QString m_fileName;
0691 
0692     int  m_time            = 0;
0693     bool m_allowDuplicates = true;
0694 
0695     /**
0696      * The average minimum widths of columns to be used in balancing calculations.
0697      */
0698     QVector<int> m_columnWeights;
0699     QVector<int> m_columnFixedWidths;
0700     QVector<int> m_weightDirty;
0701     KActionMenu *m_columnVisibleAction = nullptr;
0702     bool m_columnWidthModeChanged      = false;
0703     bool m_disableColumnWidthUpdates   = true;
0704     bool m_widthsDirty                 = true;
0705     bool m_applySharedSettings         = true;
0706 
0707     /// Used for random play and album random play
0708     PlaylistItemList m_randomSequence;
0709     QTimer          *m_refillDebounce;
0710 
0711     PlaylistSearch* m_search;
0712     bool m_searchEnabled = true;
0713 
0714     int  m_itemsLoading = 0; /// Count of pending file loads outstanding
0715     bool m_blockDataChanged = false;
0716 
0717     QAction *m_rmbEdit  = nullptr;
0718     QMenu *m_rmbMenu    = nullptr;
0719     QMenu *m_headerMenu = nullptr;
0720     WebImageFetcher *m_fetcher = nullptr;
0721 
0722     /**
0723      * This is used to indicate if the list of visible items has changed (via a
0724      * call to setVisibleItems()) while random play is playing.
0725      */
0726     static bool m_visibleChanged;
0727     static PlaylistItemList m_history;
0728     static bool m_shuttingDown;
0729     static int m_leftColumn;
0730     static QVector<PlaylistItem *> m_backMenuItems;
0731 };
0732 
0733 typedef QVector<Playlist *> PlaylistList;
0734 
0735 bool processEvents();
0736 
0737 QDataStream &operator<<(QDataStream &s, const Playlist &p);
0738 QDataStream &operator>>(QDataStream &s, Playlist &p);
0739 
0740 // template method implementations
0741 
0742 template <class ItemType>
0743 ItemType *Playlist::createItem(const FileHandle &file, QTreeWidgetItem *after)
0744 {
0745     CollectionListItem *item = collectionListItem(file);
0746     if(item && (!m_members.insert(file.absFilePath()) || m_allowDuplicates)) {
0747         auto i = new ItemType(item, this, after);
0748         setupItem(i);
0749         return i;
0750     }
0751     else
0752         return nullptr;
0753 }
0754 
0755 template <class ItemType, class SiblingType>
0756 ItemType *Playlist::createItem(SiblingType *sibling, ItemType *after)
0757 {
0758     m_disableColumnWidthUpdates = true;
0759 
0760     if(!m_members.insert(sibling->file().absFilePath()) || m_allowDuplicates) {
0761         after = new ItemType(sibling->collectionItem(), this, after);
0762         setupItem(after);
0763     }
0764 
0765     m_disableColumnWidthUpdates = false;
0766 
0767     return after;
0768 }
0769 
0770 template <template <typename> class Container, class ItemType, class SiblingType>
0771 void Playlist::createItems(const Container<SiblingType *> &siblings, ItemType *after)
0772 {
0773     if(siblings.isEmpty())
0774         return;
0775 
0776     foreach(SiblingType *sibling, siblings)
0777         after = createItem(sibling, after);
0778 
0779     playlistItemsChanged();
0780     slotWeightDirty();
0781 }
0782 
0783 #endif
0784 
0785 // vim: set et sw=4 tw=0 sta: