1 /*
2  * Cantata
3  *
4  * Copyright (c) 2017-2020 Craig Drummond <craig.p.drummond@gmail.com>
5  *
6  * ----
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; see the file COPYING.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23 
24 #ifndef BROWSE_MODEL_H
25 #define BROWSE_MODEL_H
26 
27 #include "actionmodel.h"
28 #include "mpd-interface/song.h"
29 #include "support/utils.h"
30 #include "support/icon.h"
31 #include <QMap>
32 
33 struct MPDStatsValues;
34 
35 class BrowseModel : public ActionModel
36 {
37     Q_OBJECT
38 
39 public:
40 
41     class FolderItem;
42     class Item
43     {
44     public:
45         Item(FolderItem *p=nullptr)
parent(p)46             : parent(p), row(0) { }
~Item()47         virtual ~Item() { }
48 
getChildCount()49         virtual int getChildCount() const { return 0; }
isFolder()50         virtual bool isFolder() const { return false; }
51         virtual QString getText() const =0;
52         virtual QString getSubText() const =0;
getParent()53         FolderItem * getParent() const { return parent; }
getRow()54         int getRow() const { return row; }
setRow(int r)55         void setRow(int r) { row=r; }
56 
57     private:
58         FolderItem *parent;
59         int row;
60     };
61 
62     class TrackItem : public Item
63     {
64     public:
65         TrackItem(const Song &s, FolderItem *p=nullptr)
Item(p)66             : Item(p)
67             , song(s) { }
~TrackItem()68         ~TrackItem() override { }
69 
getText()70         QString getText() const override { return song.trackAndTitleStr(); }
getSubText()71         QString getSubText() const override { return Song::Playlist==song.type || 0==song.time ? QString() : Utils::formatTime(song.time, true); }
getSong()72         const Song & getSong() const { return song; }
73 
74     private:
75         Song song;
76     };
77 
78     class FolderItem : public Item
79     {
80     public:
81         enum State {
82             State_Initial,
83             State_Fetching,
84             State_Fetched
85         };
86 
87         FolderItem(const QString &n, const QString &pth, FolderItem *p=nullptr)
Item(p)88             : Item(p), name(n), path(pth), state(State_Initial) { }
~FolderItem()89         ~FolderItem() override { }
90 
clear()91         void clear() { qDeleteAll(children); children.clear(); state=State_Initial; }
getChildren()92         const QList<Item *> getChildren() const { return children; }
getChildCount()93         int getChildCount() const override { return children.count();}
isFolder()94         bool isFolder() const override { return true; }
95         void add(Item *i);
getText()96         QString getText() const override { return name; }
getSubText()97         QString getSubText() const override { return QString(); }
getPath()98         const QString & getPath() const { return path; }
canFetchMore()99         bool canFetchMore() const { return State_Initial==state; }
isFetching()100         bool isFetching() const { return State_Fetching==state; }
setState(State s)101         void setState(State s) { state=s; }
102         QStringList allEntries(bool allowPlaylists) const;
103 
104     private:
105         QString name;
106         QString path;
107         QList<Item *> children;
108         State state;
109     };
110 
111     BrowseModel(QObject *p);
112 
113     QString name() const;
114     QString title() const;
115     QString descr() const;
icon()116     const QIcon & icon() const { return icn; }
117     void clear();
118     void load();
isEnabled()119     bool isEnabled() const { return enabled; }
120     void setEnabled(bool e);
121     Qt::ItemFlags flags(const QModelIndex &index) const override;
122     QModelIndex index(int row, int column, const QModelIndex &parent) const override;
123     QModelIndex parent(const QModelIndex &child) const override;
124     int rowCount(const QModelIndex &parent) const override;
125     int columnCount(const QModelIndex &parent) const override;
126     bool hasChildren(const QModelIndex &index) const override;
127     bool canFetchMore(const QModelIndex &index) const override;
128     void fetchMore(const QModelIndex &index) override;
129     QVariant data(const QModelIndex &index, int role) const override;
130     QMimeData * mimeData(const QModelIndexList &indexes) const override;
131     QList<Song> songs(const QModelIndexList &indexes, bool allowPlaylists) const;
132 
133 Q_SIGNALS:
134     void listFolder(const QString &path);
135 
136 private Q_SLOTS:
137     void connectionChanged();
138     void statsUpdated(const MPDStatsValues &stats);
139     void folderContents(const QString &path, const QStringList &folders, const QList<Song> &songs);
140 
141 private:
toItem(const QModelIndex & index)142     Item * toItem(const QModelIndex &index) const { return index.isValid() ? static_cast<Item*>(index.internalPointer()) : root; }
143 
144 private:
145     QIcon icn;
146     FolderItem *root;
147     QMap<QString, FolderItem *> folderIndex;
148     bool enabled;
149     time_t dbVersion;
150 };
151 
152 #endif
153