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