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