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