Fixed settings save bug
[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 <QTimer>
31 #include <QQueue>
32 #include <QMessageBox>
33 #include "config.h"
34 #include <QSpacerItem>
35
36 using namespace SomePlayer::DataObjects;
37 using namespace SomePlayer::Storage;
38
39 inline QString __format_track_string(TrackMetadata meta) {
40         int minutes = meta.length() / 60;
41         int seconds = meta.length() % 60;
42         QTime time(0, minutes, seconds);
43         return QString("[%1] %2").arg(time.toString("mm:ss")).arg(meta.title());
44
45 }
46
47 inline void __fill_model(QStandardItemModel *model, QList<QString> data) {
48         model->clear();
49         int count = data.count();
50         model->setRowCount(count);
51         for (int i = 0; i < count; i++) {
52                 model->setItem(i, 0, new QStandardItem(data.at(i)));
53         }
54 }
55
56 inline void __fill_model_tracks (QStandardItemModel *model, QList<Track> tracks) {
57         int count = tracks.count();
58         model->setRowCount(count);
59         Config config;
60         bool show_lenght = (config.getValue("ui/showtracklenght").toString() != "no");
61         for (int i = 0; i < count; i++) {
62                 TrackMetadata meta = tracks.at(i).metadata();
63                 if (show_lenght)
64                         model->setItem(i, 0, new QStandardItem(__format_track_string(meta)));
65                 else
66                         model->setItem(i, 0, new QStandardItem(meta.title()));
67         }
68 }
69
70 LibraryForm::LibraryForm(Library *lib, QWidget *parent) :
71     QWidget(parent),
72     ui(new Ui::LibraryForm)
73 {
74         _lib = lib;
75         _model = new QStandardItemModel(this);
76         _state = STATE_NONE;
77         _tools_widget = new ToolsWidget(this);
78         ui->setupUi(this);
79         ui->toolsLayout->addWidget(_tools_widget);
80         _tools_widget->hide();
81         connect(ui->playerButton, SIGNAL(clicked()), this, SLOT(_player()));
82         connect(ui->viewButton, SIGNAL(clicked()), this, SLOT(_view_button()));
83         connect(ui->playlistsButton, SIGNAL(clicked()), this, SLOT(_playlists_button()));
84         connect(ui->dynamicButton, SIGNAL(clicked()), this, SLOT(_dynamic_button()));
85         connect(ui->listView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(_process_list_click(QModelIndex)));
86         connect(ui->addButton, SIGNAL(clicked()), this, SLOT(_add_button()));
87         connect(ui->selectAllButton, SIGNAL(clicked()), this, SLOT(_toggle_select_all_button()));
88         connect(ui->backButton, SIGNAL(clicked()), this, SLOT(_back_button()));
89         connect(ui->deleteButton, SIGNAL(clicked()), this, SLOT(_delete_button()));
90         connect(ui->useButton, SIGNAL(clicked()), this, SLOT(_use_button()));
91         connect(_tools_widget, SIGNAL(search(QString)), this, SLOT(search(QString)));
92         connect(_tools_widget, SIGNAL(nextSearch()), this, SLOT(nextItem()));
93         connect(_tools_widget, SIGNAL(prevSearch()), this, SLOT(prevItem()));
94         connect(_tools_widget, SIGNAL(toggleFullscreen(bool)), this, SIGNAL(fullscreen(bool)));
95         connect(ui->moreButton, SIGNAL(clicked()), this, SLOT(_more_button()));
96         _view_button();
97         _current_playlist_changed = true;
98 }
99
100 LibraryForm::~LibraryForm()
101 {
102         _lib->saveCurrentPlaylist(_lib->getCurrentPlaylist()); // wtf?
103         _current_playlist_changed = true;
104         delete ui;
105 }
106
107 void LibraryForm::_player() {
108         emit player(_current_playlist_changed);
109         _current_playlist_changed = false;
110 }
111
112 void LibraryForm::_view_button() {
113         QList<QString> artitst = _lib->getArtists();
114         __fill_model(_model, artitst);
115         ui->listView->setModel(_model);
116         _state = STATE_ARTIST;
117         ui->backButton->setEnabled(false);
118         ui->listLabel->setText("Artists");
119         ui->addButton->setEnabled(true);
120         ui->addButton->setIcon(QIcon(":/icons/white/add.png"));
121         ui->deleteButton->setEnabled(false);
122         ui->deleteButton->setIcon(QIcon());
123         ui->useButton->setEnabled(false);
124         ui->useButton->setIcon(QIcon());
125 }
126
127 void LibraryForm::_dynamic_button() {
128         ui->useButton->setEnabled(false);
129         ui->useButton->setIcon(QIcon());
130         ui->backButton->setEnabled(false);
131         ui->addButton->setEnabled(true);
132         ui->addButton->setIcon(QIcon(":/icons/white/add.png"));
133         ui->deleteButton->setEnabled(false);
134         ui->deleteButton->setIcon(QIcon());
135         _model->clear();
136         _model->setRowCount(4);
137         _model->setItem(0, new QStandardItem("Favorites"));
138         _model->setItem(1, new QStandardItem("Most played"));
139         _model->setItem(2, new QStandardItem("Never played"));
140         _model->setItem(3, new QStandardItem("Recently added"));
141         ui->listLabel->setText("Dynamic playlists");
142         _state = STATE_DYNAMIC;
143 }
144
145 void LibraryForm::_process_list_click(QModelIndex index) {
146         if (_state == STATE_NONE) return;
147         QString data = index.data().toString();
148         switch (_state) {
149         case STATE_ARTIST:
150                 __fill_model(_model, _lib->getAlbumsForArtist(data));
151                 ui->listView->scrollToTop();
152                 _current_artist = data;
153                 _state = STATE_ALBUM;
154                 ui->backButton->setEnabled(true);
155                 ui->listLabel->setText(QString("Albums by \"%1\"").arg(_current_artist));
156                 break;
157         case STATE_ALBUM:
158                 _current_album = data;
159                 _current_tracks = _lib->getTracksForAlbum(data, _current_artist);
160                 __fill_model_tracks(_model, _current_tracks);
161                 ui->listView->scrollToTop();
162                 _state = STATE_TRACK;
163                 ui->backButton->setEnabled(true);
164                 ui->listLabel->setText(QString("Tracks from \"%1\" by \"%2\"").arg(_current_album).arg(_current_artist));
165                 break;
166         case STATE_PLAYLIST:
167                 {
168                         _current_playlist = _lib->getPlaylist(data);
169                         _current_tracks = _current_playlist.tracks();
170                         __fill_model_tracks(_model, _current_tracks);
171                         ui->listView->scrollToTop();
172                         _state = STATE_PLAYLIST_TRACK;
173                         ui->backButton->setEnabled(true);
174                         ui->deleteButton->setEnabled(true);
175                         ui->deleteButton->setIcon(QIcon(":/icons/white/delete.png"));
176                         ui->useButton->setEnabled(true);
177                         ui->useButton->setIcon(QIcon(":/icons/white/use.png"));
178                         ui->listLabel->setText(QString("Tracks in playlist \"%1\"").arg(data));
179                 }
180                 break;
181         case STATE_DYNAMIC:
182                 {
183                         switch(index.row()) {
184                         case 0: //favorites
185                                 _current_playlist = _lib->getFavorites();
186                                 break;
187                         case 1: //most played
188                                 _current_playlist = _lib->getMostPlayed();
189                                 break;
190                         case 2: //never played
191                                 _current_playlist = _lib->getNeverPlayed();
192                         case 3: //recently added
193                                 _current_playlist = _lib->getRecentlyAdded();
194                                 break;
195                         default:
196                                 return;
197                         }
198                         _current_tracks = _current_playlist.tracks();
199                         __fill_model_tracks(_model, _current_tracks);
200                         ui->listView->scrollToTop();
201                         _state = STATE_PLAYLIST_TRACK;
202                         ui->backButton->setEnabled(true);
203                         ui->useButton->setEnabled(true);
204                         ui->useButton->setIcon(QIcon(":/icons/white/use.png"));
205                         ui->addButton->setEnabled(true);
206                         ui->addButton->setIcon(QIcon(":/icons/white/add.png"));
207                         ui->listLabel->setText(_current_playlist.name());
208                 }
209         default:
210                 return;
211         }
212         QTimer::singleShot(100, ui->listView, SLOT(clearSelection())); // workaround
213 }
214
215 void LibraryForm::_add_button() {
216         if (_state == STATE_NONE) return;
217         QModelIndexList selected = ui->listView->selectionModel()->selectedIndexes();
218         ui->listView->selectionModel()->clearSelection();
219         emit busy(QString("<H1>Adding... Please wait</H1>"));
220         switch (_state) {
221         case STATE_ARTIST:
222                 foreach (QModelIndex id, selected) {
223                         _add_artist(id.data().toString());
224                 }
225                 break;
226         case STATE_ALBUM:
227                 foreach (QModelIndex id, selected) {
228                         _add_album(_current_artist, id.data().toString());
229                 }
230                 break;
231         case STATE_TRACK:
232                 foreach (QModelIndex id, selected) {
233                         _add_track(_current_tracks.at(id.row()));
234                 }
235                 break;
236         case STATE_PLAYLIST:
237                 foreach (QModelIndex id, selected) {
238                         _add_playlist(id.data().toString());
239                 }
240                 break;
241         case STATE_PLAYLIST_TRACK:
242                 foreach (QModelIndex id, selected) {
243                         _add_track(_current_tracks.at(id.row()));
244                 }
245                 break;
246         default:
247                 emit done();
248                 return;
249         }
250         emit done();
251 }
252
253
254 void LibraryForm::_add_artist(QString artist) {
255         QList<QString> albums = _lib->getAlbumsForArtist(artist);
256         foreach(QString album, albums) {
257                 _add_album(artist, album);
258         }
259 }
260
261 void LibraryForm::_add_album(QString artist, QString album) {
262         QList<Track> tracks = _lib->getTracksForAlbum(album, artist);
263         foreach(Track track, tracks) {
264                 _add_track(track);
265         }
266 }
267
268 void LibraryForm::_add_track(Track track) {
269         Playlist current = _lib->getCurrentPlaylist();
270         current.addTrack(track);
271         _lib->saveCurrentPlaylist(current);
272         _current_playlist_changed = true;
273 }
274
275 void LibraryForm::_add_playlist(QString name) {
276         Playlist playlist = _lib->getPlaylist(name);
277         QList<Track> tracks = playlist.tracks();
278         foreach (Track track, tracks) {
279                 _add_track(track);
280         }
281 }
282
283 void LibraryForm::_back_button() {
284         switch (_state) {
285         case STATE_ALBUM:
286                 _view_button();
287                 ui->listView->scrollToTop();
288                 break;
289         case STATE_TRACK:
290                 __fill_model(_model, _lib->getAlbumsForArtist(_current_artist));
291                 ui->listView->scrollToTop();
292                 _state = STATE_ALBUM;
293                 ui->listLabel->setText(QString("Albums by \"%1\"").arg(_current_artist));
294                 break;
295         case STATE_PLAYLIST_TRACK:
296                 _playlists_button();
297                 ui->listView->scrollToTop();
298         default:
299                 return;
300         }
301 }
302
303 void LibraryForm::_playlists_button() {
304         QList<QString> playlists = _lib->getPlaylistsNames();
305         __fill_model(_model, playlists);
306         ui->listView->setModel(_model);
307         _state = STATE_PLAYLIST;
308         ui->backButton->setEnabled(false);
309         ui->listLabel->setText("Playlists");
310         ui->addButton->setEnabled(false);
311         ui->addButton->setIcon(QIcon());
312         ui->deleteButton->setEnabled(true);
313         ui->deleteButton->setIcon(QIcon(":/icons/white/delete.png"));
314         ui->useButton->setEnabled(false);
315         ui->useButton->setIcon(QIcon());
316 }
317
318 void LibraryForm::_delete_button() {
319         if (_state == STATE_PLAYLIST_TRACK) {
320                 QModelIndexList selected = ui->listView->selectionModel()->selectedIndexes();
321                 ui->listView->selectionModel()->clearSelection();
322                 QQueue<int> to_delete;
323                 foreach (QModelIndex id, selected) {
324                         to_delete.append(id.row());
325                 }
326                 qSort(to_delete);
327                 int count = to_delete.count();
328                 for (int i = count-1; i >= 0; i--) {
329                         _current_playlist.removeTrackAt(to_delete.at(i));
330                 }
331                 _current_tracks = _current_playlist.tracks();
332                 _lib->savePlaylist(_current_playlist);
333                 _current_playlist_changed = true;
334                 __fill_model_tracks(_model, _current_tracks);
335         } else if (_state == STATE_PLAYLIST) {
336                 QModelIndexList selected = ui->listView->selectionModel()->selectedIndexes();
337                 QQueue<int> to_delete;
338                 foreach (QModelIndex id, selected) {
339                         to_delete.append(id.row());
340                 }
341                 qSort(to_delete);
342                 int count = to_delete.count();
343                 for (int i = count-1; i >= 0; i--) {
344                         QString name = _model->item(to_delete.at(i))->text();
345                         if (name != _CURRENT_PLAYLIST_SUBST_) {
346                                 _lib->removePlaylist(name);
347                                 _model->removeRow(to_delete.at(i));
348                         }
349                 }
350         }
351 }
352
353 void LibraryForm::_delete_track(Track track) {
354         Playlist current = _lib->getCurrentPlaylist();
355         current.removeTrack(track);
356         _lib->saveCurrentPlaylist(current);
357         _current_playlist_changed = true;
358 }
359
360 void LibraryForm::_use_button() {
361         _lib->saveCurrentPlaylist(_current_playlist);
362         _current_playlist_changed = true;
363         _current_playlist = _lib->getCurrentPlaylist();
364 }
365
366 void LibraryForm::search(QString pattern) {
367         _search_pattern = pattern;
368         _search_current_id = -1;
369         nextItem();
370 }
371
372 void LibraryForm::nextItem() {
373         QString data = _model->index(_search_current_id, 0).data().toString();
374         for (int i = _search_current_id+1; i < _model->rowCount(); i++) {
375                 data = _model->index(i, 0).data().toString();
376                 if (data.contains(_search_pattern, Qt::CaseInsensitive)) {
377                         _search_current_id = i;
378                         break;
379                 }
380         }
381         QModelIndex id = _model->index(_search_current_id, 0);
382         ui->listView->selectionModel()->clearSelection();
383         ui->listView->selectionModel()->select(id, QItemSelectionModel::Select);
384         ui->listView->scrollTo(id);
385 }
386
387 void LibraryForm::prevItem() {
388         QString data = _model->index(_search_current_id, 0).data().toString();
389         for (int i = _search_current_id-1; i >= 0; i--) {
390                 data = _model->index(i, 0).data().toString();
391                 if (data.contains(_search_pattern, Qt::CaseInsensitive)) {
392                         _search_current_id = i;
393                         break;
394                 }
395         }
396         QModelIndex id = _model->index(_search_current_id, 0);
397         ui->listView->selectionModel()->clearSelection();
398         ui->listView->selectionModel()->select(id, QItemSelectionModel::Select);
399         ui->listView->scrollTo(id);
400 }
401
402 void LibraryForm::cancelSearch() {
403         _search_pattern = "";
404         ui->listView->selectionModel()->clearSelection();
405 }
406
407 void LibraryForm::refresh() {
408         switch (_state) {
409         case STATE_ARTIST:
410                 _view_button();
411                 break;
412         case STATE_ALBUM:
413                 __fill_model(_model, _lib->getAlbumsForArtist(_current_artist));
414                 break;
415         case STATE_PLAYLIST:
416                 _playlists_button();
417                 break;
418         case STATE_DYNAMIC:
419                 _dynamic_button();
420                 break;
421         case STATE_PLAYLIST_TRACK:
422                 _current_playlist = _lib->getPlaylist(_current_playlist.name());
423                 _current_tracks = _current_playlist.tracks();
424                 __fill_model_tracks(_model, _current_tracks);
425                 break;
426         case STATE_TRACK:
427                 _current_tracks = _lib->getTracksForAlbum(_current_album, _current_artist);
428                 __fill_model_tracks(_model, _current_tracks);
429                 break;
430         default:
431                 return;
432         }
433 }
434
435 void LibraryForm::_toggle_select_all_button() {
436         if (ui->listView->selectionModel()->selectedIndexes().count() == ui->listView->model()->rowCount()) {
437                 ui->listView->selectionModel()->clearSelection();
438                 ui->selectAllButton->setIcon(QIcon(":/icons/white/select_all.png"));
439         } else {
440                 ui->listView->selectAll();
441                 ui->selectAllButton->setIcon(QIcon(":/icons/white/deselect_all.png"));
442         }
443 }
444
445 void LibraryForm::landscapeMode() {
446 }
447
448 void LibraryForm::portraitMode() {
449 }
450
451 void LibraryForm::_more_button() {
452         if (_tools_widget->isVisible()) {
453                 ui->moreButton->setIcon(QIcon(":/icons/white/more.png"));
454                 _tools_widget->hide();
455                 _tools_widget->reset();
456                 cancelSearch();
457         } else {
458                 ui->moreButton->setIcon(QIcon(":/icons/white/unmore.png"));
459                 _tools_widget->show();
460                 _tools_widget->setFocus();
461         }
462 }