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