1 /*
2 * Cantata
3 *
4 * Copyright (c) 2011-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 #include "mpdbrowsepage.h"
25 #include "mpd-interface/mpdconnection.h"
26 #include "settings.h"
27 #include "support/messagebox.h"
28 #include "support/action.h"
29 #include "support/utils.h"
30 #include "support/monoicon.h"
31 #include "models/mpdlibrarymodel.h"
32 #include "widgets/menubutton.h"
33 #include "widgets/icons.h"
34 #include "stdactions.h"
35 #include "customactions.h"
36 #include <QDesktopServices>
37 #include <QUrl>
38
MpdBrowsePage(QWidget * p)39 MpdBrowsePage::MpdBrowsePage(QWidget *p)
40 : SinglePageWidget(p)
41 , model(this)
42 {
43 QColor col=Utils::monoIconColor();
44 browseAction = new Action(MonoIcon::icon(FontAwesome::folderopen, col), tr("Open In File Manager"), this);
45 connect(view, SIGNAL(itemsSelected(bool)), this, SLOT(controlActions()));
46 connect(view, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(itemDoubleClicked(const QModelIndex &)));
47 connect(view, SIGNAL(headerClicked(int)), SLOT(headerClicked(int)));
48 connect(browseAction, SIGNAL(triggered()), this, SLOT(openFileManager()));
49 connect(MPDConnection::self(), SIGNAL(updatingFileList()), view, SLOT(updating()));
50 connect(MPDConnection::self(), SIGNAL(updatedFileList()), view, SLOT(updated()));
51 connect(MPDConnection::self(), SIGNAL(updatingDatabase()), view, SLOT(updating()));
52 connect(MPDConnection::self(), SIGNAL(updatedDatabase()), view, SLOT(updated()));
53 Configuration config(metaObject()->className());
54 view->setMode(ItemView::Mode_DetailedTree);
55 view->load(config);
56 MenuButton *menu=new MenuButton(this);
57 menu->addActions(createViewActions(QList<ItemView::Mode>() << ItemView::Mode_BasicTree << ItemView::Mode_SimpleTree
58 << ItemView::Mode_DetailedTree));
59 init(ReplacePlayQueue|AppendToPlayQueue, QList<QWidget *>() << menu);
60
61 view->addAction(StdActions::self()->addToStoredPlaylistAction);
62 view->addAction(CustomActions::self());
63 #ifdef TAGLIB_FOUND
64 #ifdef ENABLE_DEVICES_SUPPORT
65 view->addAction(StdActions::self()->copyToDeviceAction);
66 #endif
67 view->addAction(StdActions::self()->organiseFilesAction);
68 view->addAction(StdActions::self()->editTagsAction);
69 #ifdef ENABLE_REPLAYGAIN_SUPPORT
70 view->addAction(StdActions::self()->replaygainAction);
71 #endif // TAGLIB_FOUND
72 #endif
73 view->addAction(browseAction);
74 #ifdef ENABLE_DEVICES_SUPPORT
75 view->addSeparator();
76 view->addAction(StdActions::self()->deleteSongsAction);
77 #endif
78 view->setModel(&model);
79 view->closeSearch();
80 view->alwaysShowHeader();
81 connect(view, SIGNAL(updateToPlayQueue(QModelIndex,bool)), this, SLOT(updateToPlayQueue(QModelIndex,bool)));
82 view->setInfoText(tr("No folders? Looks like your MPD is not configured correctly."));
83 }
84
~MpdBrowsePage()85 MpdBrowsePage::~MpdBrowsePage()
86 {
87 Configuration config(metaObject()->className());
88 view->save(config);
89 }
90
showEvent(QShowEvent * e)91 void MpdBrowsePage::showEvent(QShowEvent *e)
92 {
93 view->focusView();
94 SinglePageWidget::showEvent(e);
95 model.setEnabled(true);
96 model.load();
97 }
98
controlActions()99 void MpdBrowsePage::controlActions()
100 {
101 QModelIndexList selected=view->selectedIndexes(false); // Dont need sorted selection here...
102 bool enable=selected.count()>0;
103 bool trackSelected=false;
104 bool folderSelected=false;
105
106 for (const QModelIndex &idx: selected) {
107 if (static_cast<BrowseModel::Item *>(idx.internalPointer())->isFolder()) {
108 folderSelected=true;
109 } else {
110 trackSelected=true;
111 }
112 }
113
114 StdActions::self()->enableAddToPlayQueue(enable);
115 StdActions::self()->addToStoredPlaylistAction->setEnabled(enable);
116 bool fileActions = trackSelected && !folderSelected && MPDConnection::self()->getDetails().dirReadable;
117 CustomActions::self()->setEnabled(fileActions);
118 #ifdef TAGLIB_FOUND
119 StdActions::self()->organiseFilesAction->setEnabled(fileActions);
120 StdActions::self()->editTagsAction->setEnabled(StdActions::self()->organiseFilesAction->isEnabled());
121 #ifdef ENABLE_REPLAYGAIN_SUPPORT
122 StdActions::self()->replaygainAction->setEnabled(StdActions::self()->organiseFilesAction->isEnabled());
123 #endif
124 #ifdef ENABLE_DEVICES_SUPPORT
125 StdActions::self()->deleteSongsAction->setEnabled(StdActions::self()->organiseFilesAction->isEnabled());
126 StdActions::self()->copyToDeviceAction->setEnabled(StdActions::self()->organiseFilesAction->isEnabled());
127 #endif
128 #endif // TAGLIB_FOUND
129
130 browseAction->setEnabled(enable && 1==selected.count() && folderSelected);
131 }
132
itemDoubleClicked(const QModelIndex &)133 void MpdBrowsePage::itemDoubleClicked(const QModelIndex &)
134 {
135 const QModelIndexList selected = view->selectedIndexes(false); // Dont need sorted selection here...
136 if (1!=selected.size()) {
137 return; //doubleclick should only have one selected item
138 }
139
140 if (!static_cast<BrowseModel::Item *>(selected.at(0).internalPointer())->isFolder()) {
141 addSelectionToPlaylist();
142 }
143 }
144
openFileManager()145 void MpdBrowsePage::openFileManager()
146 {
147 const QModelIndexList selected = view->selectedIndexes(false); // Dont need sorted selection here...
148 if (1!=selected.size()) {
149 return;
150 }
151
152 BrowseModel::Item *item = static_cast<BrowseModel::Item *>(selected.at(0).internalPointer());
153 if (item->isFolder()) {
154 QDesktopServices::openUrl(QUrl::fromLocalFile(MPDConnection::self()->getDetails().dir+static_cast<BrowseModel::FolderItem *>(item)->getPath()));
155 }
156 }
157
updateToPlayQueue(const QModelIndex & idx,bool replace)158 void MpdBrowsePage::updateToPlayQueue(const QModelIndex &idx, bool replace)
159 {
160 BrowseModel::Item *item = static_cast<BrowseModel::Item *>(idx.internalPointer());
161 if (item->isFolder()) {
162 emit add(QStringList() << MPDConnection::constDirPrefix+static_cast<BrowseModel::FolderItem *>(item)->getPath(),
163 replace ? MPDConnection::ReplaceAndplay : MPDConnection::Append, 0, false);
164 }
165 }
166
headerClicked(int level)167 void MpdBrowsePage::headerClicked(int level)
168 {
169 if (0==level) {
170 emit close();
171 }
172 }
173
selectedSongs(bool allowPlaylists) const174 QList<Song> MpdBrowsePage::selectedSongs(bool allowPlaylists) const
175 {
176 return model.songs(view->selectedIndexes(), allowPlaylists);
177 }
178
selectedFiles(bool allowPlaylists) const179 QStringList MpdBrowsePage::selectedFiles(bool allowPlaylists) const
180 {
181 QList<Song> songs=selectedSongs(allowPlaylists);
182 QStringList files;
183 for (const Song &s: songs) {
184 files.append(s.file);
185 }
186 return files;
187 }
188
addSelectionToPlaylist(const QString & name,int action,quint8 priority,bool decreasePriority)189 void MpdBrowsePage::addSelectionToPlaylist(const QString &name, int action, quint8 priority, bool decreasePriority)
190 {
191 QModelIndexList selected=view->selectedIndexes();
192 QStringList dirs;
193 QStringList files;
194
195 for (const QModelIndex &idx: selected) {
196 if (static_cast<BrowseModel::Item *>(idx.internalPointer())->isFolder()) {
197 files+=static_cast<BrowseModel::FolderItem *>(idx.internalPointer())->allEntries(false);
198 } else {
199 files.append(static_cast<BrowseModel::TrackItem *>(idx.internalPointer())->getSong().file);
200 }
201 }
202
203 if (!files.isEmpty()) {
204 if (name.isEmpty()) {
205 emit add(files, action, priority, decreasePriority);
206 } else {
207 emit addSongsToPlaylist(name, files);
208 }
209 view->clearSelection();
210 }
211 }
212
213 #ifdef ENABLE_DEVICES_SUPPORT
addSelectionToDevice(const QString & udi)214 void MpdBrowsePage::addSelectionToDevice(const QString &udi)
215 {
216 QList<Song> songs=selectedSongs();
217
218 if (!songs.isEmpty()) {
219 emit addToDevice(QString(), udi, songs);
220 view->clearSelection();
221 }
222 }
223
deleteSongs()224 void MpdBrowsePage::deleteSongs()
225 {
226 QList<Song> songs=selectedSongs();
227
228 if (!songs.isEmpty()) {
229 if (MessageBox::Yes==MessageBox::warningYesNo(this, tr("Are you sure you wish to delete the selected songs?\n\nThis cannot be undone."),
230 tr("Delete Songs"), StdGuiItem::del(), StdGuiItem::cancel())) {
231 emit deleteSongs(QString(), songs);
232 }
233 view->clearSelection();
234 }
235 }
236 #endif
237
238 #include "moc_mpdbrowsepage.cpp"
239