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