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