Added D-Bus support
[someplayer] / src / libraryform.cpp
1 /*
2  * SomePlayer - An alternate music player for Maemo 5
3  * Copyright (C) 2010 Nikolay (somebody) Tischenko <niktischenko@gmail.com>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18  */
19
20 #include "libraryform.h"
21 #include "ui_libraryform.h"
22 #include "library.h"
23 #include <QStandardItemModel>
24 #include <QStandardItem>
25 #include <QModelIndex>
26 #include <QModelIndexList>
27 #include "track.h"
28 #include "playlist.h"
29 #include <QTime>
30 #include <QQueue>
31 #include <QMessageBox>
32 #include "config.h"
33
34 using namespace SomePlayer::DataObjects;
35 using namespace SomePlayer::Storage;
36
37 inline QString __format_track_string(TrackMetadata meta) {
38         int minutes = meta.length() / 60;
39         int seconds = meta.length() % 60;
40         QTime time(0, minutes, seconds);
41         return QString("[%1] %2").arg(time.toString("mm:ss")).arg(meta.title());
42
43 }
44
45 inline void __fill_model(QStandardItemModel *model, QList<QString> data) {
46         model->clear();
47         int count = data.count();
48         model->setRowCount(count);
49         for (int i = 0; i < count; i++) {
50                 model->setItem(i, 0, new QStandardItem(data.at(i)));
51         }
52 }
53
54 inline void __fill_model_tracks (QStandardItemModel *model, QList<Track> tracks) {
55         int count = tracks.count();
56         model->setRowCount(count);
57         Config config;
58         bool show_lenght = (config.getValue("ui/showtracklenght").toString() != "no");
59         for (int i = 0; i < count; i++) {
60                 TrackMetadata meta = tracks.at(i).metadata();
61                 if (show_lenght)
62                         model->setItem(i, 0, new QStandardItem(__format_track_string(meta)));
63                 else
64                         model->setItem(i, 0, new QStandardItem(meta.title()));
65         }
66 }
67
68 LibraryForm::LibraryForm(Library *lib, QWidget *parent) :
69     QWidget(parent),
70     ui(new Ui::LibraryForm)
71 {
72         _lib = lib;
73         _model = new QStandardItemModel(this);
74         _state = STATE_NONE;
75         ui->setupUi(this);
76         connect(ui->playerButton, SIGNAL(clicked()), this, SLOT(_player()));
77         connect(ui->viewButton, SIGNAL(clicked()), this, SLOT(_view_button()));
78         connect(ui->playlistsButton, SIGNAL(clicked()), this, SLOT(_playlists_button()));
79         connect(ui->dynamicButton, SIGNAL(clicked()), this, SLOT(_dynamic_button()));
80         connect(ui->listView, SIGNAL(clicked(QModelIndex)), this, SLOT(_process_list_click(QModelIndex)));
81         connect(ui->addButton, SIGNAL(clicked()), this, SLOT(_add_button()));
82         connect(ui->selectAllButton, SIGNAL(clicked()), this, SLOT(_toggle_select_all_button()));
83         connect(ui->backButton, SIGNAL(clicked()), this, SLOT(_back_button()));
84         connect(ui->deleteButton, SIGNAL(clicked()), this, SLOT(_delete_button()));
85         connect(ui->useButton, SIGNAL(clicked()), this, SLOT(_use_button()));
86         _view_button();
87         Config config;
88         _icons_theme = config.getValue("ui/iconstheme").toString();
89         _current_playlist_changed = true;
90         setAttribute(Qt::WA_Maemo5StackedWindow);
91 }
92
93 LibraryForm::~LibraryForm()
94 {
95         _lib->saveCurrentPlaylist(_lib->getCurrentPlaylist()); // wtf?
96         _current_playlist_changed = true;
97         delete ui;
98 }
99
100 void LibraryForm::_player() {
101         emit player(_current_playlist_changed);
102         _current_playlist_changed = false;
103 }
104
105 void LibraryForm::_view_button() {
106         QList<QString> artitst = _lib->getArtists();
107         __fill_model(_model, artitst);
108         ui->listView->setModel(_model);
109         _state = STATE_ARTIST;
110         ui->backButton->hide();
111         ui->listLabel->setText("Artists");
112         ui->addButton->show();
113         ui->deleteButton->hide();
114         ui->useButton->hide();
115 }
116
117 void LibraryForm::_dynamic_button() {
118         ui->useButton->hide();
119         ui->backButton->hide();
120         ui->addButton->show();
121         ui->deleteButton->hide();
122         _model->clear();
123         _model->setRowCount(4);
124         _model->setItem(0, new QStandardItem("Favorites"));
125         _model->setItem(1, new QStandardItem("Most played"));
126         _model->setItem(2, new QStandardItem("Never played"));
127         _model->setItem(3, new QStandardItem("Recently added"));
128         ui->listLabel->setText("Dynamic playlists");
129         _state = STATE_DYNAMIC;
130 }
131
132 void LibraryForm::_process_list_click(QModelIndex index) {
133         if (_state == STATE_NONE) return;
134         QString data = index.data().toString();
135         switch (_state) {
136         case STATE_ARTIST:
137                 __fill_model(_model, _lib->getAlbumsForArtist(data));
138                 ui->listView->scrollToTop();
139                 _current_artist = data;
140                 _state = STATE_ALBUM;
141                 ui->backButton->show();
142                 ui->listLabel->setText(QString("Albums by \"%1\"").arg(_current_artist));
143                 break;
144         case STATE_ALBUM:
145                 _current_album = data;
146                 _current_tracks = _lib->getTracksForAlbum(data, _current_artist);
147                 __fill_model_tracks(_model, _current_tracks);
148                 ui->listView->scrollToTop();
149                 _state = STATE_TRACK;
150                 ui->backButton->show();
151                 ui->listLabel->setText(QString("Tracks from \"%1\" by \"%2\"").arg(_current_album).arg(_current_artist));
152                 break;
153         case STATE_PLAYLIST:
154                 {
155                         _current_playlist = _lib->getPlaylist(data);
156                         _current_tracks = _current_playlist.tracks();
157                         __fill_model_tracks(_model, _current_tracks);
158                         ui->listView->scrollToTop();
159                         _state = STATE_PLAYLIST_TRACK;
160                         ui->backButton->show();
161                         ui->deleteButton->show();
162                         ui->useButton->show();
163                         ui->listLabel->setText(QString("Tracks in playlist \"%1\"").arg(data));
164                 }
165                 break;
166         case STATE_DYNAMIC:
167                 {
168                         switch(index.row()) {
169                         case 0: //favorites
170                                 _current_playlist = _lib->getFavorites();
171                                 break;
172                         case 1: //most played
173                                 _current_playlist = _lib->getMostPlayed();
174                                 break;
175                         case 2: //never played
176                                 _current_playlist = _lib->getNeverPlayed();
177                         case 3: //recently added
178                                 _current_playlist = _lib->getRecentlyAdded();
179                                 break;
180                         default:
181                                 return;
182                         }
183                         _current_tracks = _current_playlist.tracks();
184                         __fill_model_tracks(_model, _current_tracks);
185                         ui->listView->scrollToTop();
186                         _state = STATE_PLAYLIST_TRACK;
187                         ui->backButton->show();
188                         ui->useButton->show();
189                         ui->addButton->show();
190                         ui->listLabel->setText(_current_playlist.name());
191                 }
192         default:
193                 return;
194         }
195 }
196
197 void LibraryForm::_add_button() {
198         if (_state == STATE_NONE) return;
199         QModelIndexList selected = ui->listView->selectionModel()->selectedIndexes();
200         ui->listView->selectionModel()->clearSelection();
201         emit busy(QString("<H1>Adding... Please wait</H1>"));
202         switch (_state) {
203         case STATE_ARTIST:
204                 foreach (QModelIndex id, selected) {
205                         _add_artist(id.data().toString());
206                 }
207                 break;
208         case STATE_ALBUM:
209                 foreach (QModelIndex id, selected) {
210                         _add_album(_current_artist, id.data().toString());
211                 }
212                 break;
213         case STATE_TRACK:
214                 foreach (QModelIndex id, selected) {
215                         _add_track(_current_tracks.at(id.row()));
216                 }
217                 break;
218         case STATE_PLAYLIST:
219                 foreach (QModelIndex id, selected) {
220                         _add_playlist(id.data().toString());
221                 }
222                 break;
223         case STATE_PLAYLIST_TRACK:
224                 foreach (QModelIndex id, selected) {
225                         _add_track(_current_tracks.at(id.row()));
226                 }
227                 break;
228         default:
229                 emit done();
230                 return;
231         }
232         emit done();
233 }
234
235
236 void LibraryForm::_add_artist(QString artist) {
237         QList<QString> albums = _lib->getAlbumsForArtist(artist);
238         foreach(QString album, albums) {
239                 _add_album(artist, album);
240         }
241 }
242
243 void LibraryForm::_add_album(QString artist, QString album) {
244         QList<Track> tracks = _lib->getTracksForAlbum(album, artist);
245         foreach(Track track, tracks) {
246                 _add_track(track);
247         }
248 }
249
250 void LibraryForm::_add_track(Track track) {
251         Playlist current = _lib->getCurrentPlaylist();
252         current.addTrack(track);
253         _lib->saveCurrentPlaylist(current);
254         _current_playlist_changed = true;
255 }
256
257 void LibraryForm::_add_playlist(QString name) {
258         Playlist playlist = _lib->getPlaylist(name);
259         QList<Track> tracks = playlist.tracks();
260         foreach (Track track, tracks) {
261                 _add_track(track);
262         }
263 }
264
265 void LibraryForm::_back_button() {
266         switch (_state) {
267         case STATE_ALBUM:
268                 _view_button();
269                 ui->listView->scrollToTop();
270                 break;
271         case STATE_TRACK:
272                 __fill_model(_model, _lib->getAlbumsForArtist(_current_artist));
273                 ui->listView->scrollToTop();
274                 _state = STATE_ALBUM;
275                 ui->listLabel->setText(QString("Albums by \"%1\"").arg(_current_artist));
276                 break;
277         case STATE_PLAYLIST_TRACK:
278                 _playlists_button();
279                 ui->listView->scrollToTop();
280         default:
281                 return;
282         }
283 }
284
285 void LibraryForm::_playlists_button() {
286         QList<QString> playlists = _lib->getPlaylistsNames();
287         __fill_model(_model, playlists);
288         ui->listView->setModel(_model);
289         _state = STATE_PLAYLIST;
290         ui->backButton->hide();
291         ui->listLabel->setText("Playlists");
292         ui->addButton->hide();
293         ui->deleteButton->show();
294         ui->useButton->hide();
295 }
296
297 void LibraryForm::_delete_button() {
298         if (_state == STATE_PLAYLIST_TRACK) {
299                 QModelIndexList selected = ui->listView->selectionModel()->selectedIndexes();
300                 ui->listView->selectionModel()->clearSelection();
301                 QQueue<int> to_delete;
302                 foreach (QModelIndex id, selected) {
303                         to_delete.append(id.row());
304                 }
305                 qSort(to_delete);
306                 int count = to_delete.count();
307                 for (int i = count-1; i >= 0; i--) {
308                         _current_playlist.removeTrackAt(to_delete.at(i));
309                 }
310                 _current_tracks = _current_playlist.tracks();
311                 _lib->savePlaylist(_current_playlist);
312                 __fill_model_tracks(_model, _current_tracks);
313         } else if (_state == STATE_PLAYLIST) {
314                 QModelIndexList selected = ui->listView->selectionModel()->selectedIndexes();
315                 QQueue<int> to_delete;
316                 foreach (QModelIndex id, selected) {
317                         to_delete.append(id.row());
318                 }
319                 qSort(to_delete);
320                 int count = to_delete.count();
321                 for (int i = count-1; i >= 0; i--) {
322                         QString name = _model->item(to_delete.at(i))->text();
323                         if (name != _CURRENT_PLAYLIST_SUBST_) {
324                                 _lib->removePlaylist(name);
325                                 _model->removeRow(to_delete.at(i));
326                         }
327                 }
328         }
329 }
330
331 void LibraryForm::_delete_track(Track track) {
332         Playlist current = _lib->getCurrentPlaylist();
333         current.removeTrack(track);
334         _lib->saveCurrentPlaylist(current);
335         _current_playlist_changed = true;
336 }
337
338 void LibraryForm::_use_button() {
339         _lib->saveCurrentPlaylist(_current_playlist);
340         _current_playlist_changed = true;
341         _current_playlist = _lib->getCurrentPlaylist();
342 }
343
344 void LibraryForm::search(QString &pattern) {
345         _search_pattern = pattern;
346         _search_current_id = -1;
347         nextItem();
348 }
349
350 void LibraryForm::nextItem() {
351         QString data = _model->index(_search_current_id, 0).data().toString();
352         for (int i = _search_current_id+1; i < _model->rowCount(); i++) {
353                 data = _model->index(i, 0).data().toString();
354                 if (data.contains(_search_pattern, Qt::CaseInsensitive)) {
355                         _search_current_id = i;
356                         break;
357                 }
358         }
359         QModelIndex id = _model->index(_search_current_id, 0);
360         ui->listView->selectionModel()->clearSelection();
361         ui->listView->selectionModel()->select(id, QItemSelectionModel::Select);
362         ui->listView->scrollTo(id);
363 }
364
365 void LibraryForm::prevItem() {
366         QString data = _model->index(_search_current_id, 0).data().toString();
367         for (int i = _search_current_id-1; i >= 0; i--) {
368                 data = _model->index(i, 0).data().toString();
369                 if (data.contains(_search_pattern, Qt::CaseInsensitive)) {
370                         _search_current_id = i;
371                         break;
372                 }
373         }
374         QModelIndex id = _model->index(_search_current_id, 0);
375         ui->listView->selectionModel()->clearSelection();
376         ui->listView->selectionModel()->select(id, QItemSelectionModel::Select);
377         ui->listView->scrollTo(id);
378 }
379
380 void LibraryForm::cancelSearch() {
381         _search_pattern = "";
382         ui->listView->selectionModel()->clearSelection();
383 }
384
385 void LibraryForm::refresh() {
386         switch (_state) {
387         case STATE_ARTIST:
388                 _view_button();
389                 break;
390         case STATE_ALBUM:
391                 __fill_model(_model, _lib->getAlbumsForArtist(_current_artist));
392                 break;
393         case STATE_PLAYLIST:
394                 _playlists_button();
395                 break;
396         case STATE_DYNAMIC:
397                 _dynamic_button();
398                 break;
399         case STATE_PLAYLIST_TRACK:
400                 _current_playlist = _lib->getPlaylist(_current_playlist.name());
401                 _current_tracks = _current_playlist.tracks();
402                 __fill_model_tracks(_model, _current_tracks);
403                 break;
404         case STATE_TRACK:
405                 _current_tracks = _lib->getTracksForAlbum(_current_album, _current_artist);
406                 __fill_model_tracks(_model, _current_tracks);
407                 break;
408         default:
409                 return;
410         }
411 }
412
413 void LibraryForm::_toggle_select_all_button() {
414         if (ui->listView->selectionModel()->selectedIndexes().count() == ui->listView->model()->rowCount()) {
415                 ui->listView->selectionModel()->clearSelection();
416                 ui->selectAllButton->setIcon(QIcon(":/icons/"+_icons_theme+"/select_all.png"));
417         } else {
418                 ui->listView->selectAll();
419                 ui->selectAllButton->setIcon(QIcon(":/icons/"+_icons_theme+"/deselect_all.png"));
420         }
421 }
422
423 void LibraryForm::updateIcons() {
424         Config config;
425         _icons_theme = config.getValue("ui/iconstheme").toString();
426         ui->backButton->setIcon(QIcon(":/icons/"+_icons_theme+"/back.png"));
427         if (ui->listView->selectionModel()->selectedIndexes().count() == ui->listView->model()->rowCount())
428                 ui->selectAllButton->setIcon(QIcon(":/icons/"+_icons_theme+"/deselect_all.png"));
429         else
430                 ui->selectAllButton->setIcon(QIcon(":/icons/"+_icons_theme+"/select_all.png"));
431         ui->addButton->setIcon(QIcon(":/icons/"+_icons_theme+"/add.png"));
432         ui->deleteButton->setIcon(QIcon(":/icons/"+_icons_theme+"/delete.png"));
433         ui->useButton->setIcon(QIcon(":/icons/"+_icons_theme+"/use.png"));
434         ui->playerButton->setIcon(QIcon(":/icons/"+_icons_theme+"/player.png"));
435         ui->viewButton->setIcon(QIcon(":/icons/"+_icons_theme+"/artists.png"));
436         ui->dynamicButton->setIcon(QIcon(":/icons/"+_icons_theme+"/dynamic.png"));
437         ui->playlistsButton->setIcon(QIcon(":/icons/"+_icons_theme+"/playlists.png"));
438 }