File indexing completed on 2023-10-03 04:07:39

0001 /**
0002  * Copyright (C) 2002-2004 Scott Wheeler <wheeler@kde.org>
0003  *
0004  * This program is free software; you can redistribute it and/or modify it under
0005  * the terms of the GNU General Public License as published by the Free Software
0006  * Foundation; either version 2 of the License, or (at your option) any later
0007  * version.
0008  *
0009  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0010  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0011  * PARTICULAR PURPOSE. See the GNU General Public License for more details.
0012  *
0013  * You should have received a copy of the GNU General Public License along with
0014  * this program.  If not, see <http://www.gnu.org/licenses/>.
0015  */
0016 
0017 #ifndef JUK_COLLECTIONLIST_H
0018 #define JUK_COLLECTIONLIST_H
0019 
0020 #include <QHash>
0021 #include <QVector>
0022 #include <QReadWriteLock>
0023 
0024 #include <KFileItem>
0025 
0026 #include "playlist.h"
0027 #include "playlistitem.h"
0028 
0029 class ViewMode;
0030 class KFileItemList;
0031 class KDirWatch;
0032 
0033 /**
0034  * This type is for mapping QString track attributes like the album, artist
0035  * and track to an integer count representing the number of outstanding items
0036  * that hold the string.
0037  */
0038 
0039 typedef QHash<QString, int> TagCountDict;
0040 typedef QHashIterator<QString, int> TagCountDictIterator;
0041 
0042 /**
0043  * We then have an array of dicts, one for each column in the list view.
0044  * The array is sparse (not every vector will have a TagCountDict so we use
0045  * pointers.
0046  */
0047 
0048 typedef QVector<TagCountDict *> TagCountDicts;
0049 
0050 /**
0051  * This is the "collection", or all of the music files that have been opened
0052  * in any playlist and not explicitly removed from the collection.
0053  *
0054  * It is being implemented as a "semi-singleton" because I need universal access
0055  * to just one instance.  However, because the collection needs initialization
0056  * parameters (that will not always be available when an instance is needed).
0057  * Hence there will be the familiar singleton "instance()" method along with an
0058  * "initialize()" method.
0059  */
0060 
0061 class CollectionListItem : public PlaylistItem
0062 {
0063     friend class Playlist;
0064     friend class CollectionList;
0065     friend class PlaylistItem;
0066 
0067 public:
0068     virtual void refresh() override;
0069     PlaylistItem *itemForPlaylist(const Playlist *playlist);
0070     void updateCollectionDict(const QString &oldPath, const QString &newPath);
0071     void repaint() const;
0072     PlaylistItemList children() const { return m_children; }
0073 
0074 protected:
0075     CollectionListItem(CollectionList *parent, const FileHandle &file);
0076     virtual ~CollectionListItem();
0077 
0078     void addChildItem(PlaylistItem *child);
0079     void removeChildItem(PlaylistItem *child);
0080 
0081     /**
0082      * Returns true if the item is now up to date (even if this required a refresh) or
0083      * false if the item is invalid.
0084      */
0085     bool checkCurrent();
0086 
0087     virtual CollectionListItem *collectionItem() override { return this; }
0088 
0089 private:
0090     bool m_shuttingDown;
0091     PlaylistItemList m_children;
0092 };
0093 
0094 class CollectionList : public Playlist
0095 {
0096     friend class CollectionListItem;
0097 
0098     Q_OBJECT
0099 
0100 public:
0101     /**
0102      * A variety of unique value lists will be kept in the collection.  This
0103      * enum can be used as an index into those structures.
0104      */
0105     enum UniqueSetType { Artists = 0, Albums = 1, Genres = 2 };
0106 
0107     static CollectionList *instance();
0108     static void initialize(PlaylistCollection *collection);
0109 
0110     /**
0111      * Returns a unique set of values associated with the type specified.
0112      */
0113     QStringList uniqueSet(UniqueSetType t) const;
0114 
0115     CollectionListItem *lookup(const QString &file) const;
0116 
0117     virtual CollectionListItem *createItem(const FileHandle &file,
0118                                      QTreeWidgetItem * = nullptr) override;
0119 
0120     virtual void clearItems(const PlaylistItemList &items) override;
0121 
0122     void setupTreeViewEntries(ViewMode *viewMode) const;
0123 
0124     virtual bool canReload() const override { return true; }
0125 
0126     void saveItemsToCache() const;
0127 
0128 public slots:
0129     virtual void clear() override;
0130 
0131     void slotCheckCache();
0132 
0133     void slotRemoveItem(const QString &file);
0134     void slotRefreshItem(const QString &file);
0135 
0136     void slotNewItems(const KFileItemList &items);
0137     void slotRefreshItems(const QList<QPair<KFileItem, KFileItem> > &items);
0138     void slotDeleteItems(const KFileItemList &items);
0139 
0140 protected:
0141     CollectionList(PlaylistCollection *collection);
0142     virtual ~CollectionList();
0143 
0144     virtual void dropEvent(QDropEvent *e) override;
0145     virtual void dragMoveEvent(QDragMoveEvent *e) override;
0146 
0147     // These methods are used by CollectionListItem, which is a friend class.
0148 
0149     void addToDict(const QString &file, CollectionListItem *item);
0150     void removeFromDict(const QString &file);
0151 
0152     // These methods are also used by CollectionListItem, to manage the
0153     // strings used in generating the unique sets and tree view mode playlists.
0154 
0155     QString addStringToDict(const QString &value, int column);
0156     void removeStringFromDict(const QString &value, int column);
0157 
0158     void addWatched(const QString &file);
0159     void removeWatched(const QString &file);
0160 
0161     virtual bool hasItem(const QString &file) const override;
0162 
0163 signals:
0164     void signalCollectionChanged();
0165 
0166     /**
0167      * This is emitted when the set of columns that is visible is changed.
0168      *
0169      * \see Playlist::hideColumn()
0170      * \see Playlist::showColumn()
0171      * \see Playlist::isColumnVisible()
0172      */
0173     void signalNewTag(const QString &, unsigned);
0174     void signalRemovedTag(const QString &, unsigned);
0175 
0176     // Emitted once cached items are loaded, which allows for folder scanning
0177     // and invalid track detection to proceed.
0178     void cachedItemsLoaded();
0179 
0180 public slots:
0181     /**
0182      * Loads the CollectionListItems from the Cache.  Should be called after program
0183      * initialization.
0184      */
0185     void startLoadingCachedItems();
0186 
0187     /**
0188      * Loads a few items at a time. Intended to be single-shotted into the event
0189      * loop so that loading the music doesn't freeze the GUI.
0190      */
0191     void loadNextBatchCachedItems();
0192 
0193     /**
0194      * Teardown from cache loading (e.g. a sort operation). Should
0195      * always be called if startLoadingCachedItems is called.
0196      */
0197     void completedLoadingCachedItems();
0198 
0199 private:
0200     /**
0201      * Just the size of the above enum to keep from hard coding it in several
0202      * locations.
0203      */
0204     static const int m_uniqueSetCount = 3;
0205 
0206     static CollectionList *m_list;
0207     QHash<QString, CollectionListItem *> m_itemsDict;
0208     mutable QReadWriteLock m_itemsDictLock;
0209     KDirWatch *m_dirWatch;
0210     TagCountDicts m_columnTags;
0211 };
0212 
0213 #endif
0214 
0215 // vim: set et sw=4 tw=0 sta: