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