Flippable GUI (swap toolbars), checkbox for it in options, fixed current
[tomamp] / tomamp / mainwindow.cpp
1 #include <QtGui>
2 #include <QtDebug>
3 #include <QInputDialog>
4 #ifdef Q_WS_MAEMO_5
5 #include <QtMaemo5/QMaemo5InformationBox>
6 #endif
7 #include "mainwindow.h"
8 #include "optiondialog.h"
9 #include "time.h"
10
11 //#define AVOID_INPUT_DIALOG 0
12
13 MainWindow::MainWindow()
14     : plman (this), settings (tr ("TomAmp"), "TomAmp"), isPlaying (false)
15 {
16     setOrientation();
17     audioOutput = new Phonon::AudioOutput(Phonon::MusicCategory, this);
18     mediaObject = new Phonon::MediaObject(this);
19
20     mediaObject->setTickInterval(1000);
21     connect(mediaObject, SIGNAL(tick(qint64)), this, SLOT(tick(qint64)));
22     connect(mediaObject, SIGNAL(stateChanged(Phonon::State,Phonon::State)),
23         this, SLOT(stateChanged(Phonon::State,Phonon::State)));
24     connect(mediaObject, SIGNAL(currentSourceChanged(Phonon::MediaSource)),
25         this, SLOT(sourceChanged(Phonon::MediaSource)));
26     connect(mediaObject, SIGNAL(aboutToFinish()), this, SLOT(aboutToFinish()));
27     connect (&plman, SIGNAL (playlistChanged (int)), this, SLOT (playlistChanged(int)));
28     connect (&plman, SIGNAL (itemUpdated(int)), this, SLOT (itemUpdated (int)));
29     connect (&plman, SIGNAL (itemRemoved(int)), this, SLOT (itemRemoved (int)));
30
31     Phonon::createPath(mediaObject, audioOutput);
32
33     qsrand (time (NULL));
34     repeat = settings.value("repeat", false).toBool();
35     shuffle = settings.value("shuffle", false).toBool();
36     headers = settings.value ("headers", QStringList()).toStringList();
37     setupShuffleList();
38     setupActions();
39     setupMenus();
40 /*    if (settings.value("uiflipped", false).toBool())
41         setupUiFlipped();
42     else*/
43     setupUi ();
44     show ();
45     timeLcd->display("00:00:00");
46     plman.addStringList(settings.value("lastPlaylist").toStringList());
47     setupShuffleList();
48     int curind = settings.value("currentIndex", -1).toInt ();
49     if (curind >= 0)
50         setItem (curind, false);
51     audioOutput->setVolume(settings.value("volume", .5).toReal());
52     QApplication::setWindowIcon(QIcon (QPixmap (":images/tomamp")));
53 }
54
55 MainWindow::~MainWindow()
56 {
57     settings.setValue("shuffle", shuffle);
58     settings.setValue("repeat", repeat);
59     settings.setValue("lastPlaylist", plman.playlistStrings());
60     settings.setValue("volume", audioOutput->volume());
61     settings.setValue("currentIndex", plman.indexOf(mediaObject->currentSource()));
62     settings.setValue("headers", headers);
63     for (int i = 0; i < musicTable->columnCount(); ++i)
64     {
65         QString lab = QString ("colWidth_%1").arg (i);
66         settings.setValue(lab, musicTable->columnWidth(i));
67     }
68 }
69
70 void MainWindow::setOrientation ()
71 {
72 #ifdef Q_WS_MAEMO_5
73     QString orient = settings.value("orientation", "Automatic").toString();
74     if (orient == "Portrait")
75         setAttribute(Qt::WA_Maemo5PortraitOrientation, true);
76     else if (orient == "Landscape")
77         setAttribute(Qt::WA_Maemo5LandscapeOrientation, true);
78     else
79         setAttribute(Qt::WA_Maemo5AutoOrientation, true);
80 #endif
81 }
82
83 void MainWindow::addFiles()
84 {
85     QString folder = settings.value("LastFolder").toString();
86     if (folder.isEmpty())
87         folder = QDesktopServices::storageLocation(QDesktopServices::MusicLocation);
88     QStringList files = QFileDialog::getOpenFileNames(this, tr("Select Files To Add"),
89                     folder, "Music files (*.mp3 *.ogg *.wav *.flac);;Playlists (*.m3u *.pls)");
90
91     if (files.isEmpty())
92         return;
93
94     QString dir = QFileInfo (files[0]).absoluteDir().absolutePath();
95     settings.setValue("LastFolder", dir);
96     QStringList toadd;
97     foreach (QString string, files)
98     {
99         if (string.toLower().endsWith(".pls") || string.toLower().endsWith(".m3u"))
100             plman.addPlaylist(string);
101         else
102             toadd.append (string);
103     }
104     plman.addStringList(toadd);
105 }
106
107 void MainWindow::addFolder()
108 {
109     QString folder = settings.value("LastFolder").toString();
110     if (folder.isEmpty())
111         folder = QDesktopServices::storageLocation(QDesktopServices::MusicLocation);
112     QString dir = QFileDialog::getExistingDirectory(this,
113             tr("Select Directory To Add"),
114             folder);
115
116     if (dir.isEmpty())
117         return;
118
119     settings.setValue("LastFolder", dir);
120
121     QStringList filters;
122     QStringList files = QDir (dir).entryList(filters, QDir::AllDirs);
123     files.removeAll(".");
124     files.removeAll("..");
125     bool recursive = false;
126     if (files.size())
127         recursive = QMessageBox::question(this, "Add all folders", "Subfolders have been detected, add everything?", QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes;
128     plman.parseAndAddFolder(dir, recursive);
129 }
130
131
132 void MainWindow::addUrl()
133 {
134 #ifdef AVOID_INPUT_DIALOG
135     QString url = "http://war.str3am.com:7970";
136 #else
137     QString url = QInputDialog::getText(this, "Get URL", "Please type in the stream URL");
138 #endif
139     if (url.isEmpty() || !url.toLower().startsWith("http"))
140         return;
141     QStringList toadd;
142     toadd << url;
143     plman.addStringList(toadd);
144 }
145
146
147 void MainWindow::about()
148 {
149     QMessageBox::information(this, tr("About TomAmp v0.1"),
150         tr("TomAmp is a simple playlist-based music player.\n\n"
151         "(c) 2010 Tamas Marki <tmarki@gmail.com>\n\n"
152         "Please send comments and bug reports to the above e-mail address.\n\n"
153         "Icons by http://itweek.deviantart.com/\n\n"
154         "Special thanks to Attila Csipa"));
155 }
156
157 void MainWindow::stateChanged(Phonon::State newState, Phonon::State /* oldState */)
158 {
159     switch (newState)
160     {
161         case Phonon::ErrorState:
162             if (mediaObject->errorType() == Phonon::FatalError)
163             {
164 //                QMessageBox::warning(this, tr("Fatal Error"),
165 //                mediaObject->errorString() + mediaObject->currentSource().fileName() + ", " + mediaObject->currentSource().url().toString());
166             }
167             else
168             {
169 //                QMessageBox::warning(this, tr("Error"),
170 //                mediaObject->errorString());
171             }
172             next ();
173             break;
174         case Phonon::PlayingState:
175             setWindowTitle(mediaObject->metaData().value("TITLE") + "(" + mediaObject->metaData().value("ARTIST") + ") - TomAmp");
176             pauseAction->setVisible(true);
177             playAction->setVisible (false);
178             playAction->setEnabled(false);
179             pauseAction->setEnabled(true);
180             stopAction->setEnabled(true);
181             unhighlightRow(lastPlayed);
182             lastPlayed = plman.indexOf(mediaObject->currentSource());
183             highlightRow(plman.indexOf(mediaObject->currentSource()));
184             musicTable->selectRow(plman.indexOf(mediaObject->currentSource()));
185             break;
186         case Phonon::StoppedState:
187             setWindowTitle("TomAmp");
188             stopAction->setEnabled(false);
189             playAction->setEnabled(true);
190             pauseAction->setVisible(false);
191             playAction->setVisible(true);
192             pauseAction->setEnabled(false);
193             timeLcd->display("00:00:00");
194             unhighlightRow(plman.indexOf(mediaObject->currentSource()));
195             break;
196         case Phonon::PausedState:
197             pauseAction->setEnabled(false);
198             stopAction->setEnabled(true);
199             pauseAction->setVisible(false);
200             playAction->setVisible(true);
201             playAction->setEnabled(true);
202             break;
203         case Phonon::BufferingState:
204             break;
205         default:
206         ;
207     }
208 }
209
210 void MainWindow::next()
211 {
212     bool wasPlaying = isPlaying;
213     if (mediaObject->state () == Phonon::ErrorState)
214         wasPlaying = true;
215     if (mediaObject->queue().size())
216     {
217         setItem (plman.indexOf(mediaObject->queue()[0]), wasPlaying);
218         return;
219     }
220     int index = plman.indexOf(mediaObject->currentSource());
221     if (shuffle)
222     {
223         index = shuffleList.indexOf(plman.indexOf(mediaObject->currentSource())) + 1;
224         while (index < shuffleList.size () && !plman.getItem(shuffleList[index]).playable)
225         {
226             index += 1;
227         }
228         if (index < shuffleList.size ())
229         {
230             setItem (index, wasPlaying);
231         }
232         else if (repeat)
233         {
234             index = 0;
235             while ((index) < shuffleList.size () && !plman.getItem(shuffleList[index]).playable)
236             {
237                 index += 1;
238             }
239             setItem (index, wasPlaying);
240         }
241     }
242     else
243     {
244         index++;
245         while ((index) < plman.size () && !plman.getItem(index).playable)
246         {
247             index += 1;
248         }
249         if (index < plman.size())
250         {
251             setItem (index, wasPlaying);
252         }
253         else if (repeat)
254         {
255             index = 0;
256             while ((index) < plman.size () && !plman.getItem(index).playable)
257             {
258                 index += 1;
259             }
260             setItem (index, wasPlaying);
261         }
262     }
263 }
264
265 void MainWindow::setItem(int i, bool doplay)
266 {
267     if (i < plman.size() && i >= 0)
268     {
269 /*        if (lastPlayed >= 0)
270             unhighlightRow(lastPlayed);*/
271         if (shuffle)
272         {
273             mediaObject->setCurrentSource(plman.at (shuffleList[i]));
274         }
275         else
276         {
277             mediaObject->setCurrentSource(plman.at(i));
278         }
279     }
280     if (doplay && mediaObject->currentSource().type() != Phonon::MediaSource::Invalid)
281     {
282         play();
283     }
284     else
285         stop ();
286 }
287
288 void MainWindow::previous()
289 {
290     bool wasPlaying = isPlaying;//(mediaObject->state () == Phonon::PlayingState);
291     if (mediaObject->state () == Phonon::ErrorState)
292         wasPlaying = true;
293     int index = plman.indexOf(mediaObject->currentSource());
294     if (shuffle)
295     {
296         index = shuffleList.indexOf(plman.indexOf(mediaObject->currentSource())) - 1;
297         while (index >= 0 && !plman.getItem(shuffleList[index]).playable)
298         {
299             index--;
300         }
301         if (index >= 0)
302         {
303             setItem (index, wasPlaying);
304         }
305         else if (repeat)
306         {
307             index = plman.size () - 1;
308             while (index >= 0 && !plman.getItem(shuffleList[index]).playable)
309             {
310                 index--;
311             }
312             setItem (index, wasPlaying);
313         }
314 /*        if (index < 0)
315             wasPlaying = false;*/
316
317     }
318     else
319     {
320         index--;
321         while ((index) >= 0 && !plman.getItem(index).playable)
322         {
323             index--;
324         }
325         if (index >= 0)
326         {
327             setItem (index, wasPlaying);
328         }
329         else if (repeat)
330         {
331             index = plman.size() - 1;
332             while ((index) >= 0 && !plman.getItem(index).playable)
333             {
334                 index--;
335             }
336             setItem (index, wasPlaying);
337         }
338     }
339 }
340
341 void MainWindow::highlightRow (int i)
342 {
343     for (int j = 0; j < 3; ++j)
344     {
345         QTableWidgetItem* item = musicTable->item(i, j);
346         if (item)
347         {
348             QFont font = item->font();
349             font.setBold(true);
350             font.setItalic(true);
351             item->setFont(font);
352         }
353     }
354 }
355
356 void MainWindow::unhighlightRow (int i)
357 {
358     for (int j = 0; j < 3; ++j)
359     {
360         QTableWidgetItem* item = musicTable->item(i, j);
361         if (item)
362         {
363             QFont font = item->font();
364             font.setBold(false);
365             font.setItalic(false);
366             item->setFont(font);
367         }
368     }
369 }
370
371
372 void MainWindow::tick(qint64 time)
373 {
374     QTime displayTime((time / 3600000), (time / 60000) % 60, (time / 1000) % 60);
375
376     timeLcd->display(displayTime.toString("HH:mm:ss"));
377 }
378
379 void MainWindow::tableClicked(int row, int /* column */)
380 {
381 //    bool wasPlaying = mediaObject->state() == Phonon::PlayingState;
382
383 /*    mediaObject->stop();
384     mediaObject->clearQueue();*/
385
386     if (row >= plman.size())
387         return;
388
389     int index = row;
390     while (index < shuffleList.size () && !plman.getItem(index).playable)
391     {
392         index += 1;
393     }
394     if (plman.size() > index)
395     {
396         if (shuffle)
397             index = shuffleList.indexOf(index);
398         setItem (index, true);
399 //        mediaObject->play();
400     }
401     else
402     {
403         index = 0;
404         while (index < plman.size () && !plman.getItem(index).playable)
405         {
406             index += 1;
407         }
408         if (plman.size() > index)
409         {
410             if (shuffle)
411                 index = shuffleList.indexOf(index);
412             setItem (index, true);
413 //            mediaObject->play();
414         }
415     }
416
417 }
418
419 void MainWindow::sourceChanged(const Phonon::MediaSource &source)
420 {
421     int ind = plman.indexOf(source);
422     highlightRow(ind);
423     unhighlightRow(lastPlayed);
424     lastPlayed = ind;
425     musicTable->selectRow(ind);
426     timeLcd->display("00:00:00");
427 }
428
429
430 void MainWindow::aboutToFinish()
431 {
432     if (mediaObject->queue().size())
433         return;
434     int index = plman.indexOf(mediaObject->currentSource()) + 1;
435     if (shuffle)
436     {
437         index = shuffleList.indexOf(plman.indexOf(mediaObject->currentSource())) + 1;
438         if (index < shuffleList.size ())
439         {
440             mediaObject->enqueue(plman.at (shuffleList[index]));
441         }
442         else if (repeat)
443         {
444             mediaObject->enqueue(plman.at (shuffleList[0]));
445         }
446
447     }
448     else
449     {
450         if (plman.size() > index)
451         {
452             mediaObject->enqueue(plman.at(index));
453         }
454         else if (repeat)
455         {
456             mediaObject->enqueue(plman.at(0));
457         }
458     }
459 }
460
461 void MainWindow::finished()
462 {
463 }
464
465 void MainWindow::setupActions()
466 {
467     playAction = new QAction(QIcon (QPixmap (":images/play")), "", this);
468     playAction->setShortcut(tr("Crl+P"));
469     playAction->setDisabled(true);
470     pauseAction = new QAction(QIcon (QPixmap (":images/pause")), "", this);
471     pauseAction->setShortcut(tr("Ctrl+A"));
472     pauseAction->setDisabled(true);
473     pauseAction->setVisible(false);
474     stopAction = new QAction(QIcon (QPixmap (":images/stop")), "", this);
475     stopAction->setShortcut(tr("Ctrl+S"));
476     stopAction->setDisabled(true);
477     nextAction = new QAction(QIcon (QPixmap (":images/next")), "", this);
478     nextAction->setShortcut(tr("Ctrl+N"));
479     upAction = new QAction (QString::fromUtf8("▲"), this);
480     downAction = new QAction (QString::fromUtf8("▼"), this);
481     delAction = new QAction (QString::fromUtf8("╳"), this);
482     previousAction = new QAction(QIcon (QPixmap (":images/previous")), "", this);
483     previousAction->setShortcut(tr("Ctrl+R"));
484     if (repeat)
485         repeatAction = new QAction(QIcon (QPixmap (":images/repeatActive")), "", this);
486     else
487         repeatAction = new QAction(QIcon (QPixmap (":images/repeat")), "", this);
488     repeatAction->setCheckable(true);
489     repeatAction->setChecked(repeat);
490     repeatAction->setShortcut(tr("Ctrl+I"));
491     if (shuffle)
492         shuffleAction = new QAction(QIcon (QPixmap (":images/shuffleActive")), "", this);
493     else
494         shuffleAction = new QAction(QIcon (QPixmap (":images/shuffle")), "", this);
495     shuffleAction->setCheckable(true);
496     shuffleAction->setChecked(shuffle);
497     shuffleAction->setShortcut(tr("Ctrl+H"));
498     enqueueActionButton = new QAction (tr ("E"), this);
499     volumeAction = new QAction(QIcon (QPixmap (":images/volume")), "", this);
500     volumeAction->setCheckable(true);
501     volumeAction->setShortcut(tr("Ctrl+V"));
502     addFilesAction = new QAction(tr("Add &File"), this);
503     addFilesAction->setShortcut(tr("Ctrl+F"));
504     addFoldersAction = new QAction(tr("Add F&older"), this);
505     addFoldersAction->setShortcut(tr("Ctrl+O"));
506     addUrlAction = new QAction(tr("Add &Url"), this);
507     addUrlAction->setShortcut(tr("Ctrl+U"));
508     savePlaylistAction = new QAction (tr("Sa&ve Playlist"), this);
509     savePlaylistAction->setShortcut(tr ("Ctrl+V"));
510     loadPlaylistAction = new QAction (tr("&Load Playlist"), this);
511     loadPlaylistAction->setShortcut(tr("Ctrl+L"));
512     clearPlaylistAction = new QAction (tr("&Clear Playlist"), this);
513     clearPlaylistAction->setShortcut(tr("Ctrl+C"));
514     optionAction = new QAction (tr("Op&tions"), this);
515     optionAction->setShortcut(tr("Ctrl+T"));
516     exitAction = new QAction(tr("E&xit"), this);
517     exitAction->setShortcut(tr("Ctrl+X"));
518     aboutAction = new QAction(tr("A&bout"), this);
519     aboutAction->setShortcut(tr("Ctrl+B"));
520     aboutQtAction = new QAction(tr("About &Qt"), this);
521     aboutQtAction->setShortcut(tr("Ctrl+Q"));
522 /*    removeSelected = new QAction (tr("&Delete from playlist"));
523     removeSelected->setShortcut(tr ("Ctrl+D"));*/
524
525     connect(playAction, SIGNAL(triggered()), this, SLOT(play()));
526     connect(pauseAction, SIGNAL(triggered()), mediaObject, SLOT(pause()) );
527     connect(stopAction, SIGNAL(triggered()), this, SLOT(stop()));
528     connect(repeatAction, SIGNAL(triggered()), this, SLOT(repeatToggle()));
529     connect(shuffleAction, SIGNAL(triggered()), this, SLOT(shuffleToggle()));
530     connect(volumeAction, SIGNAL(triggered()), this, SLOT(volumeToggle()));
531     connect(enqueueActionButton, SIGNAL(triggered()), this, SLOT(enqueueSelected()));
532
533     connect(addFilesAction, SIGNAL(triggered()), this, SLOT(addFiles()));
534     connect(addFoldersAction, SIGNAL(triggered()), this, SLOT(addFolder()));
535     connect(addUrlAction, SIGNAL(triggered()), this, SLOT(addUrl()));
536     connect (savePlaylistAction, SIGNAL (triggered()), this, SLOT (savePlaylist()));
537     connect (loadPlaylistAction, SIGNAL (triggered()), this, SLOT (loadPlaylist()));
538     connect (clearPlaylistAction, SIGNAL (triggered()), &plman, SLOT (clearPlaylist()));
539     connect (optionAction, SIGNAL (triggered()), this, SLOT (showOptions()));
540     connect (nextAction, SIGNAL(triggered()), this, SLOT(next()));
541     connect (previousAction, SIGNAL(triggered()), this, SLOT(previous()));
542     connect (upAction, SIGNAL(triggered()), this, SLOT(upSelected()));
543     connect (downAction, SIGNAL(triggered()), this, SLOT(downSelected()));
544     connect (delAction, SIGNAL(triggered()), this, SLOT(removeSelectedItem()));
545     connect(exitAction, SIGNAL(triggered()), this, SLOT(close()));
546     connect(aboutAction, SIGNAL(triggered()), this, SLOT(about()));
547     connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
548 //    connect (removeSelected, SIGNAL (triggered()), this, SLOT (removeSelectedItem()));
549 }
550
551 void MainWindow::removeSelectedItem()
552 {
553     if (QMessageBox::question(this, "Confirm remove", "Are you sure you want to remove this item?", QMessageBox::Yes, QMessageBox::No) == QMessageBox::No)
554         return;
555     int row = musicTable->currentRow();
556     if (row >= 0)
557         plman.removeItem(row);
558 }
559
560 void MainWindow::removeAllButSelectedItem()
561 {
562     if (QMessageBox::question(this, "Confirm remove", "Are you sure you want to remove all other items?", QMessageBox::Yes, QMessageBox::No) == QMessageBox::No)
563         return;
564     int row = musicTable->currentRow();
565     if (row >= 0)
566     {
567         QString uri = plman.getItem(row).uri;
568         QStringList lst;
569         lst << uri;
570         plman.clearPlaylist();
571         plman.addStringList(lst);
572     }
573 }
574
575 void MainWindow::repeatToggle ()
576 {
577     repeat = !repeat;
578     settings.setValue("repeat", QVariant (repeat));
579     if (repeat)
580         repeatAction->setIcon(QIcon (QPixmap (":images/repeatActive")));
581     else
582         repeatAction->setIcon(QIcon (QPixmap (":images/repeat")));
583 }
584
585 void MainWindow::shuffleToggle ()
586 {
587     shuffle = !shuffle;
588     settings.setValue("shuffle", QVariant (shuffle));
589     if (shuffle)
590         shuffleAction->setIcon(QIcon (QPixmap (":images/shuffleActive")));
591     else
592         shuffleAction->setIcon(QIcon (QPixmap (":images/shuffle")));
593 }
594
595 void MainWindow::volumeToggle ()
596 {
597     volumeSlider->setVisible(volumeAction->isChecked());
598 }
599
600 void MainWindow::play()
601 {
602     mediaObject->play();
603 //    lastPlayed = plman.indexOf(mediaObject->currentSource());
604     highlightRow(lastPlayed);
605     isPlaying = true;
606 }
607
608 void MainWindow::stop()
609 {
610     mediaObject->stop();
611     isPlaying = false;
612 }
613
614
615 void MainWindow::setupMenus()
616 {
617     QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
618     fileMenu->addAction(addFilesAction);
619     fileMenu->addAction(addFoldersAction);
620     fileMenu->addAction(addUrlAction);
621     fileMenu->addSeparator();
622     fileMenu->addAction(savePlaylistAction);
623     fileMenu->addAction(loadPlaylistAction);
624     fileMenu->addAction(clearPlaylistAction);
625     fileMenu->addAction(optionAction);
626 //    fileMenu->addAction(exitAction);
627
628     QMenu *aboutMenu = menuBar()->addMenu(tr("&Help"));
629     aboutMenu->addAction(aboutAction);
630     aboutMenu->addAction(aboutQtAction);
631 }
632
633 void MainWindow::setupUi()
634 {
635     QToolBar *bar = new QToolBar;
636     bool flip = settings.value("uiflipped", false).toBool();
637
638     if(!flip) bar->setOrientation(Qt::Vertical);
639     bar->setStyleSheet("padding:7px");
640
641     seekSlider = new Phonon::SeekSlider(this);
642     seekSlider->setMediaObject(mediaObject);
643     if (flip) seekSlider->setOrientation(Qt::Vertical);
644
645     volumeSlider = new Phonon::VolumeSlider(this);
646     volumeSlider->setAudioOutput(audioOutput);
647     volumeSlider->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
648     if (flip) volumeSlider->setOrientation(Qt::Vertical);
649     volumeSlider->setMuteVisible(false);
650     bar->addAction(playAction);
651     bar->addAction(pauseAction);
652     bar->addAction(stopAction);
653     bar->addAction(repeatAction);
654     bar->addAction(shuffleAction);
655     bar->addAction(nextAction);
656     bar->addAction(previousAction);
657     bar->addAction(upAction);
658     bar->addAction(downAction);
659     bar->addAction(delAction);
660     bar->addAction(enqueueActionButton);
661
662     contextMenu = new QMenu (this);
663     enqueueAction = contextMenu->addAction(tr ("Enqueue"));
664     removeSelected = contextMenu->addAction(tr ("Remove selected"));
665     removeAllButSelected = contextMenu->addAction(tr("Remove all but selected"));
666     connect (removeSelected, SIGNAL (triggered()), this, SLOT (removeSelectedItem()));
667     connect (removeAllButSelected, SIGNAL (triggered()), this, SLOT (removeAllButSelectedItem()));
668     connect (enqueueAction, SIGNAL (triggered()), this, SLOT (enqueueSelected()));
669
670
671     timeLcd = new QLCDNumber;
672
673     if (!headers.size ())
674     {
675         headers << "Artist" << "Title" << "Album";
676         settings.setValue("headers", headers);
677     }
678
679     musicTable = new QTableWidget(0, headers.size ());
680     musicTable->setHorizontalHeaderLabels(headers);
681     musicTable->setSelectionMode(QAbstractItemView::SingleSelection);
682     musicTable->setSelectionBehavior(QAbstractItemView::SelectRows);
683     connect(musicTable, SIGNAL(cellDoubleClicked(int,int)),
684         this, SLOT(tableClicked(int,int)));
685     connect(musicTable, SIGNAL(cellClicked(int,int)),
686         this, SLOT(cellClicked(int,int)));
687     for (int i = 0; i < musicTable->columnCount(); ++i)
688     {
689         QString lab = QString ("colWidth_%1").arg (i);
690         int val = settings.value(lab, 0).toInt();
691         if (val)
692             musicTable->setColumnWidth(i, val);
693     }
694
695
696     QLayout *seekerLayout;
697     QLayout *playbackLayout;
698     if (flip)
699     {
700         seekerLayout = new QVBoxLayout;
701         playbackLayout = new QHBoxLayout;
702         bar->addWidget(timeLcd);
703     }
704     else
705     {
706         seekerLayout = new QHBoxLayout;
707         playbackLayout = new QVBoxLayout;
708     }
709     QToolBar* bar2 = new QToolBar;
710     bar2->addAction(volumeAction);
711     seekerLayout->addWidget(bar2);
712     seekerLayout->addWidget(volumeSlider);
713     seekerLayout->addWidget(seekSlider);
714     if (!flip)
715         seekerLayout->addWidget(timeLcd);
716     volumeSlider->hide ();
717     playbackLayout->addWidget(bar);
718
719     QVBoxLayout *seekAndTableLayout = new QVBoxLayout;
720
721     seekAndTableLayout->addWidget(musicTable);
722     QHBoxLayout *mainLayout = new QHBoxLayout;
723     mainLayout->addLayout(seekAndTableLayout);
724     if (flip)
725     {
726         seekAndTableLayout->addLayout(playbackLayout);
727         mainLayout->addLayout(seekerLayout);
728     }
729     else
730     {
731         seekAndTableLayout->addLayout(seekerLayout);
732         mainLayout->addLayout(playbackLayout);
733     }
734
735
736     QWidget *widget = new QWidget;
737     widget->setLayout(mainLayout);
738
739     setCentralWidget(widget);
740     setWindowTitle("TomAmp");
741 }
742
743 void MainWindow::cellClicked(int /*row*/, int)
744 {
745 }
746
747 void MainWindow::enqueueSelected()
748 {
749     int sel = musicTable->currentRow();
750     if (sel >= 0)
751     {
752         mediaObject->queue().clear();
753         mediaObject->enqueue(plman.at(sel));
754 #ifdef Q_WS_MAEMO_5
755         QMaemo5InformationBox::information(this, tr ("Song enqueued as next song"),
756         QMaemo5InformationBox::DefaultTimeout);
757 #endif
758
759     }
760 }
761
762 void MainWindow::contextMenuEvent (QContextMenuEvent*e)
763 {
764     if (!childAt (e->pos()))
765         return;
766     if (childAt (e->pos())->parentWidget() != musicTable)
767         return;
768     contextMenu->popup(e->globalPos());
769 }
770
771
772 void MainWindow::setupShuffleList()
773 {
774     QList<int> tmp;
775     int index = plman.indexOf(mediaObject->currentSource());
776     if (index < 0)
777         index = 0;
778     for (int i = 0; i < plman.size(); ++i)
779     {
780         if ((i != index))
781             tmp.append(i);
782     }
783     shuffleList.clear();
784     shuffleList.append (index);
785     while (tmp.size ())
786     {
787         int ind = qrand () % tmp.size();
788         shuffleList.append(tmp[ind]);
789         tmp.removeAt(ind);
790     }
791 }
792
793 void MainWindow::savePlaylist ()
794 {
795     QString filename = QFileDialog::getSaveFileName(this, tr("Please select file name"), "", "Playlist Files (*.m3u *.pls)");
796     if (filename.isEmpty())
797         return;
798     plman.savePlaylist(filename);
799 }
800
801 void MainWindow::loadPlaylist ()
802 {
803     QString filename = QFileDialog::getOpenFileName(this, tr("Select playlist file to load"), "", "*.m3u *.pls");
804     if (filename.isEmpty())
805         return;
806     plman.loadPlaylist (filename);
807 }
808
809 void MainWindow::playlistChanged(int from)
810 {
811     while (musicTable->rowCount() > from)
812     {
813         musicTable->removeRow(musicTable->rowCount () - 1);
814     }
815     int firstGood = -1;
816     for (int i = from; i < plman.size (); ++i)
817     {
818         if (firstGood < 0 && plman.getItem (i).playable)
819             firstGood = i;
820         int currentRow = musicTable->rowCount();
821         musicTable->insertRow(currentRow);
822         setRowFromItem (currentRow, plman.getItem(i));
823     }
824 /*    if (plman.indexOf(mediaObject->currentSource()) < 0)
825     {
826         setItem (firstGood, false);
827     }*/
828     setupShuffleList();
829 }
830
831 void MainWindow::setRowFromItem (int row, const PlaylistItem& item)
832 {
833     if (row >= musicTable->rowCount())
834         return;
835     if (item.artist.isEmpty() && item.title.isEmpty())
836     {
837         int col = headers.indexOf("Title");
838         if (col >= 0)
839         {
840             QTableWidgetItem *item1 = new QTableWidgetItem(item.uri);
841             item1->setFlags(item1->flags() ^ Qt::ItemIsEditable);
842             musicTable->setItem(row, col, item1);
843         }
844     }
845     else
846     {
847         int col = headers.indexOf("Artist");
848         if (col >= 0)
849         {
850             QTableWidgetItem *item1 = new QTableWidgetItem(item.artist);
851             item1->setFlags(item1->flags() ^ Qt::ItemIsEditable);
852             musicTable->setItem(row, col, item1);
853         }
854         col = headers.indexOf("Title");
855         if (col >= 0)
856         {
857             if (!musicTable->item (row, col))
858             {
859                 QTableWidgetItem *item2 = new QTableWidgetItem(item.title);
860                 item2->setFlags(item2->flags() ^ Qt::ItemIsEditable);
861                 musicTable->setItem(row, col, item2);
862             }
863             else
864             {
865                 musicTable->item (row, col)->setText(item.title);
866             }
867         }
868         col = headers.indexOf("Album");
869         if (col >= 0)
870         {
871             QTableWidgetItem *item3 = new QTableWidgetItem(item.album);
872             item3->setFlags(item3->flags() ^ Qt::ItemIsEditable);
873             musicTable->setItem(row, col, item3);
874         }
875     }
876
877     int controlCol = headers.indexOf("Controls");
878     if (controlCol >= 0 && !musicTable->cellWidget(row, controlCol))
879     {
880         QLabel* label = new QLabel;
881         label->setText(QString::fromUtf8("<b><a style='text-decoration:none' href='up'>▲</a> <a style='text-decoration:none' href='down'>▼</a> <a style='text-decoration:none' href='del'>╳</a> <a style='text-decoration:none' href='info'>i</a></b>"));
882         label->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
883         label->setProperty("row", row);
884         musicTable->setCellWidget(row, controlCol, label);
885         connect (label, SIGNAL (linkActivated (const QString&)),  this, SLOT (playlistControl (const QString&)));
886     }
887 }
888
889 void MainWindow::playlistControl (const QString& con)
890 {
891     int i = sender ()->property("row").toInt();
892     qDebug () << "Playlist control: " << con << " on " << i;
893     if (con == "up")
894         buttonUp(i);
895     else if (con == "down")
896         buttonDown(i);
897     else if (con == "del")
898         buttonDel (i);
899     else
900         QMessageBox::information(this, tr ("Coming up..."), tr ("This feature is not implemented yet."));
901 }
902
903
904 void MainWindow::buttonUp(int i)
905 {
906     qDebug () << "Presses up on " << i;
907     if (i)
908     {
909         plman.moveItemUp(i);
910         setRowFromItem (i, plman.getItem(i));
911         setRowFromItem (i - 1, plman.getItem(i - 1));
912         int controlCol = headers.indexOf("Controls");
913         if (controlCol >= 0)
914         {
915             musicTable->cellWidget(i, controlCol)->setProperty("row", i);
916             musicTable->cellWidget(i - 1, controlCol)->setProperty("row", i - 1);
917         }
918         musicTable->selectRow(i - 1);
919     }
920 }
921
922 void MainWindow::buttonDown(int i)
923 {
924     qDebug () << "Presses down on " << i;
925     if (i < plman.size() - 1)
926     {
927         plman.moveItemDown(i);
928         setRowFromItem (i, plman.getItem(i));
929         setRowFromItem (i + 1, plman.getItem(i + 1));
930         int controlCol = headers.indexOf("Controls");
931         if (controlCol >= 0)
932         {
933             musicTable->cellWidget(i, controlCol)->setProperty("row", i);
934             musicTable->cellWidget(i + 1, controlCol)->setProperty("row", i + 1);
935         }
936         musicTable->selectRow(i + 1);
937     }
938 }
939
940 void MainWindow::buttonDel(int i)
941 {
942     qDebug () << "Presses del on " << i;
943     if (QMessageBox::question(this, "Confirm remove", "Are you sure you want to remove this item?", QMessageBox::Yes, QMessageBox::No) == QMessageBox::No)
944         return;
945     if (i < plman.size())
946     {
947         plman.removeItem(i);
948     }
949 }
950
951 void MainWindow::itemUpdated(int index)
952 {
953     if (plman.indexOf(mediaObject->currentSource()) < 0 && plman.getItem (index).playable)
954     {
955         setItem (index, false);
956     }
957     setRowFromItem (index, plman.getItem(index));
958     if (plman.indexOf(mediaObject->currentSource()) == index)
959     {
960         if (shuffle) index = shuffleList.indexOf(index);
961         setItem (index, false);
962     }
963 }
964
965 void MainWindow::itemRemoved (int i)
966 {
967     musicTable->removeRow(i);
968     int controlCol = headers.indexOf("Controls");
969     if (controlCol < 0)
970         return;
971     for (int j = i ? (i - 1) : 0; j < musicTable->rowCount(); ++j)
972     {
973         if (musicTable->cellWidget(j, controlCol))
974             musicTable->cellWidget(j, controlCol)->setProperty("row", j);
975     }
976 }
977
978 void MainWindow::upSelected()
979 {
980     int sel = musicTable->currentRow();
981     if (sel > 0)
982         buttonUp(sel);
983 }
984
985 void MainWindow::downSelected()
986 {
987     int sel = musicTable->currentRow();
988     if (sel >= 0)
989         buttonDown(sel);
990 }
991
992
993
994 void MainWindow::showOptions ()
995 {
996     bool flip = settings.value("uiflipped", false).toBool();
997     OptionDialog* dlg = new OptionDialog (this, settings);
998     dlg->exec();
999     delete dlg;
1000     if (flip != settings.value("uiflipped", false).toBool())
1001     {
1002         delete centralWidget();
1003         setupUi ();
1004     }
1005     setOrientation ();
1006     if (headers != settings.value("headers", QStringList ()).toStringList())
1007     {
1008         headers = settings.value("headers", QStringList ()).toStringList();
1009         musicTable->setColumnCount(headers.size ());
1010         musicTable->setHorizontalHeaderLabels(headers);
1011         playlistChanged(0);
1012     }
1013 }