Fixed bug with focus on search line
[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 }
91
92 LibraryForm::~LibraryForm()
93 {
94         _lib->saveCurrentPlaylist(_lib->getCurrentPlaylist()); // wtf?
95         _current_playlist_changed = true;
96         delete ui;
97 }
98
99 void LibraryForm::_player() {
100         emit player(_current_playlist_changed);
101         _current_playlist_changed = false;
102 }
103
104 void LibraryForm::_view_button() {
105         QList<QString> artitst = _lib->getArtists();
106         __fill_model(_model, artitst);
107         ui->listView->setModel(_model);
108         _state = STATE_ARTIST;
109         ui->backButton->hide();
110         ui->listLabel->setText("Artists");
111         ui->addButton->show();
112         ui->deleteButton->hide();
113         ui->useButton->hide();
114 }
115
116 void LibraryForm::_dynamic_button() {
117         ui->useButton->hide();
118         ui->backButton->hide();
119         ui->addButton->show();
120         ui->deleteButton->hide();
121         _model->clear();
122         _model->setRowCount(4);
123         _model->setItem(0, new QStandardItem("Favorites"));
124         _model->setItem(1, new QStandardItem("Most played"));
125         _model->setItem(2, new QStandardItem("Never played"));
126         _model->setItem(3, new QStandardItem("Recently added"));
127         ui->listLabel->setText("Dynamic playlists");
128         _state = STATE_DYNAMIC;
129 }
130
131 void LibraryForm::_process_list_click(QModelIndex index) {
132         if (_state == STATE_NONE) return;
133         QString data = index.data().toString();
134         switch (_state) {
135         case STATE_ARTIST:
136                 __fill_model(_model, _lib->getAlbumsForArtist(data));
137                 ui->listView->scrollToTop();
138                 _current_artist = data;
139                 _state = STATE_ALBUM;
140                 ui->backButton->show();
141                 ui->listLabel->setText(QString("Albums by \"%1\"").arg(_current_artist));
142                 break;
143         case STATE_ALBUM:
144                 _current_album = data;
145                 _current_tracks = _lib->getTracksForAlbum(data, _current_artist);
146                 __fill_model_tracks(_model, _current_tracks);
147                 ui->listView->scrollToTop();
148                 _state = STATE_TRACK;
149                 ui->backButton->show();
150                 ui->listLabel->setText(QString("Tracks from \"%1\" by \"%2\"").arg(_current_album).arg(_current_artist));
151                 break;
152         case STATE_PLAYLIST:
153                 {
154                         _current_playlist = _lib->getPlaylist(data);
155                         _current_tracks = _current_playlist.tracks();
156                         __fill_model_tracks(_model, _current_tracks);
157                         ui->listView->scrollToTop();
158                         _state = STATE_PLAYLIST_TRACK;
159                         ui->backButton->show();
160                         ui->deleteButton->show();
161                         ui->useButton->show();
162                         ui->listLabel->setText(QString("Tracks in playlist \"%1\"").arg(data));
163                 }
164                 break;
165         case STATE_DYNAMIC:
166                 {
167                         switch(index.row()) {
168                         case 0: //favorites
169                                 _current_playlist = _lib->getFavorites();
170                                 break;
171                         case 1: //most played
172                                 _current_playlist = _lib->getMostPlayed();
173                                 break;
174                         case 2: //never played
175                                 _current_playlist = _lib->getNeverPlayed();
176                         case 3: //recently added
177                                 _current_playlist = _lib->getRecentlyAdded();
178                                 break;
179                         default:
180                                 return;
181                         }
182                         _current_tracks = _current_playlist.tracks();
183                         __fill_model_tracks(_model, _current_tracks);
184                         ui->listView->scrollToTop();
185                         _state = STATE_PLAYLIST_TRACK;
186                         ui->backButton->show();
187                         ui->useButton->show();
188                         ui->addButton->show();
189                         ui->listLabel->setText(_current_playlist.name());
190                 }
191         default:
192                 return;
193         }
194 }
195
196 void LibraryForm::_add_button() {
197         if (_state == STATE_NONE) return;
198         QModelIndexList selected = ui->listView->selectionModel()->selectedIndexes();
199         ui->listView->selectionModel()->clearSelection();
200         emit busy(QString("<H1>Adding... Please wait</H1>"));
201         switch (_state) {
202         case STATE_ARTIST:
203                 foreach (QModelIndex id, selected) {
204                         _add_artist(id.data().toString());
205                 }
206                 break;
207         case STATE_ALBUM:
208                 foreach (QModelIndex id, selected) {
209                         _add_album(_current_artist, id.data().toString());
210                 }
211                 break;
212         case STATE_TRACK:
213                 foreach (QModelIndex id, selected) {
214                         _add_track(_current_tracks.at(id.row()));
215                 }
216                 break;
217         case STATE_PLAYLIST:
218                 foreach (QModelIndex id, selected) {
219                         _add_playlist(id.data().toString());
220                 }
221                 break;
222         case STATE_PLAYLIST_TRACK:
223                 foreach (QModelIndex id, selected) {
224                         _add_track(_current_tracks.at(id.row()));
225                 }
226                 break;
227         default:
228                 emit done();
229                 return;
230         }
231         emit done();
232 }
233
234
235 void LibraryForm::_add_artist(QString artist) {
236         QList<QString> albums = _lib->getAlbumsForArtist(artist);
237         foreach(QString album, albums) {
238                 _add_album(artist, album);
239         }
240 }
241
242 void LibraryForm::_add_album(QString artist, QString album) {
243         QList<Track> tracks = _lib->getTracksForAlbum(album, artist);
244         foreach(Track track, tracks) {
245                 _add_track(track);
246         }
247 }
248
249 void LibraryForm::_add_track(Track track) {
250         Playlist current = _lib->getCurrentPlaylist();
251         current.addTrack(track);
252         _lib->saveCurrentPlaylist(current);
253         _current_playlist_changed = true;
254 }
255
256 void LibraryForm::_add_playlist(QString name) {
257         Playlist playlist = _lib->getPlaylist(name);
258         QList<Track> tracks = playlist.tracks();
259         foreach (Track track, tracks) {
260                 _add_track(track);
261         }
262 }
263
264 void LibraryForm::_back_button() {
265         switch (_state) {
266         case STATE_ALBUM:
267                 _view_button();
268                 ui->listView->scrollToTop();
269                 break;
270         case STATE_TRACK:
271                 __fill_model(_model, _lib->getAlbumsForArtist(_current_artist));
272                 ui->listView->scrollToTop();
273                 _state = STATE_ALBUM;
274                 ui->listLabel->setText(QString("Albums by \"%1\"").arg(_current_artist));
275                 break;
276         case STATE_PLAYLIST_TRACK:
277                 _playlists_button();
278                 ui->listView->scrollToTop();
279         default:
280                 return;
281         }
282 }
283
284 void LibraryForm::_playlists_button() {
285         QList<QString> playlists = _lib->getPlaylistsNames();
286         __fill_model(_model, playlists);
287         ui->listView->setModel(_model);
288         _state = STATE_PLAYLIST;
289         ui->backButton->hide();
290         ui->listLabel->setText("Playlists");
291         ui->addButton->hide();
292         ui->deleteButton->show();
293         ui->useButton->hide();
294 }
295
296 void LibraryForm::_delete_button() {
297         if (_state == STATE_PLAYLIST_TRACK) {
298                 QModelIndexList selected = ui->listView->selectionModel()->selectedIndexes();
299                 ui->listView->selectionModel()->clearSelection();
300                 QQueue<int> to_delete;
301                 foreach (QModelIndex id, selected) {
302                         to_delete.append(id.row());
303                 }
304                 qSort(to_delete);
305                 int count = to_delete.count();
306                 for (int i = count-1; i >= 0; i--) {
307                         _current_playlist.removeTrackAt(to_delete.at(i));
308                 }
309                 _current_tracks = _current_playlist.tracks();
310                 _lib->savePlaylist(_current_playlist);
311                 __fill_model_tracks(_model, _current_tracks);
312         } else if (_state == STATE_PLAYLIST) {
313                 QModelIndexList selected = ui->listView->selectionModel()->selectedIndexes();
314                 QQueue<int> to_delete;
315                 foreach (QModelIndex id, selected) {
316                         to_delete.append(id.row());
317                 }
318                 qSort(to_delete);
319                 int count = to_delete.count();
320                 for (int i = count-1; i >= 0; i--) {
321                         QString name = _model->item(to_delete.at(i))->text();
322                         if (name != _CURRENT_PLAYLIST_SUBST_) {
323                                 _lib->removePlaylist(name);
324                                 _model->removeRow(to_delete.at(i));
325                         }
326                 }
327         }
328 }
329
330 void LibraryForm::_delete_track(Track track) {
331         Playlist current = _lib->getCurrentPlaylist();
332         current.removeTrack(track);
333         _lib->saveCurrentPlaylist(current);
334         _current_playlist_changed = true;
335 }
336
337 void LibraryForm::_use_button() {
338         _lib->saveCurrentPlaylist(_current_playlist);
339         _current_playlist_changed = true;
340         _current_playlist = _lib->getCurrentPlaylist();
341 }
342
343 void LibraryForm::search(QString &pattern) {
344         _search_pattern = pattern;
345         _search_current_id = -1;
346         nextItem();
347 }
348
349 void LibraryForm::nextItem() {
350         QString data = _model->index(_search_current_id, 0).data().toString();
351         for (int i = _search_current_id+1; i < _model->rowCount(); i++) {
352                 data = _model->index(i, 0).data().toString();
353                 if (data.contains(_search_pattern, Qt::CaseInsensitive)) {
354                         _search_current_id = i;
355                         break;
356                 }
357         }
358         QModelIndex id = _model->index(_search_current_id, 0);
359         ui->listView->selectionModel()->clearSelection();
360         ui->listView->selectionModel()->select(id, QItemSelectionModel::Select);
361         ui->listView->scrollTo(id);
362 }
363
364 void LibraryForm::prevItem() {
365         QString data = _model->index(_search_current_id, 0).data().toString();
366         for (int i = _search_current_id-1; i >= 0; i--) {
367                 data = _model->index(i, 0).data().toString();
368                 if (data.contains(_search_pattern, Qt::CaseInsensitive)) {
369                         _search_current_id = i;
370                         break;
371                 }
372         }
373         QModelIndex id = _model->index(_search_current_id, 0);
374         ui->listView->selectionModel()->clearSelection();
375         ui->listView->selectionModel()->select(id, QItemSelectionModel::Select);
376         ui->listView->scrollTo(id);
377 }
378
379 void LibraryForm::cancelSearch() {
380         _search_pattern = "";
381         ui->listView->selectionModel()->clearSelection();
382 }
383
384 void LibraryForm::refresh() {
385         switch (_state) {
386         case STATE_ARTIST:
387                 _view_button();
388                 break;
389         case STATE_ALBUM:
390                 __fill_model(_model, _lib->getAlbumsForArtist(_current_artist));
391                 break;
392         case STATE_PLAYLIST:
393                 _playlists_button();
394                 break;
395         case STATE_DYNAMIC:
396                 _dynamic_button();
397                 break;
398         case STATE_PLAYLIST_TRACK:
399                 _current_playlist = _lib->getPlaylist(_current_playlist.name());
400                 _current_tracks = _current_playlist.tracks();
401                 __fill_model_tracks(_model, _current_tracks);
402                 break;
403         case STATE_TRACK:
404                 _current_tracks = _lib->getTracksForAlbum(_current_album, _current_artist);
405                 __fill_model_tracks(_model, _current_tracks);
406                 break;
407         default:
408                 return;
409         }
410 }
411
412 void LibraryForm::_toggle_select_all_button() {
413         if (ui->listView->selectionModel()->selectedIndexes().count() == ui->listView->model()->rowCount()) {
414                 ui->listView->selectionModel()->clearSelection();
415                 ui->selectAllButton->setIcon(QIcon(":/icons/"+_icons_theme+"/select_all.png"));
416         } else {
417                 ui->listView->selectAll();
418                 ui->selectAllButton->setIcon(QIcon(":/icons/"+_icons_theme+"/deselect_all.png"));
419         }
420 }
421
422 void LibraryForm::updateIcons() {
423         Config config;
424         _icons_theme = config.getValue("ui/iconstheme").toString();
425         ui->backButton->setIcon(QIcon(":/icons/"+_icons_theme+"/back.png"));
426         if (ui->listView->selectionModel()->selectedIndexes().count() == ui->listView->model()->rowCount())
427                 ui->selectAllButton->setIcon(QIcon(":/icons/"+_icons_theme+"/deselect_all.png"));
428         else
429                 ui->selectAllButton->setIcon(QIcon(":/icons/"+_icons_theme+"/select_all.png"));
430         ui->addButton->setIcon(QIcon(":/icons/"+_icons_theme+"/add.png"));
431         ui->deleteButton->setIcon(QIcon(":/icons/"+_icons_theme+"/delete.png"));
432         ui->useButton->setIcon(QIcon(":/icons/"+_icons_theme+"/use.png"));
433         ui->playerButton->setIcon(QIcon(":/icons/"+_icons_theme+"/player.png"));
434         ui->viewButton->setIcon(QIcon(":/icons/"+_icons_theme+"/artists.png"));
435         ui->dynamicButton->setIcon(QIcon(":/icons/"+_icons_theme+"/dynamic.png"));
436         ui->playlistsButton->setIcon(QIcon(":/icons/"+_icons_theme+"/playlists.png"));
437 }