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