]> git.sur5r.net Git - minitube/blob - src/MainWindow.cpp
Reenable seekbar on Linux
[minitube] / src / MainWindow.cpp
1 #include "MainWindow.h"
2 #include "spacer.h"
3 #include "constants.h"
4 #include "iconloader/qticonloader.h"
5 #include "global.h"
6 #include "videodefinition.h"
7 #include "fontutils.h"
8 #include "globalshortcuts.h"
9 #ifdef Q_WS_X11
10 #include "gnomeglobalshortcutbackend.h"
11 #endif
12 #ifdef APP_MAC
13 // #include "local/mac/mac_startup.h"
14 #endif
15 #include "downloadmanager.h"
16 #include "youtubesuggest.h"
17
18 MainWindow::MainWindow() :
19         aboutView(0),
20         downloadView(0),
21         mediaObject(0),
22         audioOutput(0),
23         m_fullscreen(false) {
24
25     // views mechanism
26     history = new QStack<QWidget*>();
27     views = new QStackedWidget(this);
28     setCentralWidget(views);
29
30     // views
31     searchView = new SearchView(this);
32     connect(searchView, SIGNAL(search(SearchParams*)), this, SLOT(showMedia(SearchParams*)));
33     views->addWidget(searchView);
34
35     mediaView = new MediaView(this);
36     views->addWidget(mediaView);
37
38     toolbarSearch = new SearchLineEdit(this);
39     toolbarSearch->setMinimumWidth(toolbarSearch->fontInfo().pixelSize()*15);
40     toolbarSearch->setSuggester(new YouTubeSuggest(this));
41     connect(toolbarSearch, SIGNAL(search(const QString&)), this, SLOT(startToolbarSearch(const QString&)));
42
43     // build ui
44     createActions();
45     createMenus();
46     createToolBars();
47     createStatusBar();
48
49     initPhonon();
50     // mediaView->setSlider(slider);
51     mediaView->setMediaObject(mediaObject);
52
53     // remove that useless menu/toolbar context menu
54     this->setContextMenuPolicy(Qt::NoContextMenu);
55
56     // mediaView init stuff thats needs actions
57     mediaView->initialize();
58
59     // event filter to block ugly toolbar tooltips
60     qApp->installEventFilter(this);
61
62     // restore window position
63     readSettings();
64
65     // show the initial view
66     showWidget(searchView);
67
68     // Global shortcuts
69     GlobalShortcuts &shortcuts = GlobalShortcuts::instance();
70 #ifdef Q_WS_X11
71     if (GnomeGlobalShortcutBackend::IsGsdAvailable())
72         shortcuts.setBackend(new GnomeGlobalShortcutBackend(&shortcuts));
73 #endif
74 #ifdef APP_MAC
75     // mac::MacSetup();
76 #endif
77     connect(&shortcuts, SIGNAL(PlayPause()), pauseAct, SLOT(trigger()));
78     connect(&shortcuts, SIGNAL(Stop()), this, SLOT(stop()));
79     connect(&shortcuts, SIGNAL(Next()), skipAct, SLOT(trigger()));
80
81     connect(DownloadManager::instance(), SIGNAL(statusMessageChanged(QString)),
82             SLOT(updateDownloadMessage(QString)));
83     connect(DownloadManager::instance(), SIGNAL(finished()),
84             SLOT(downloadsFinished()));
85 }
86
87 MainWindow::~MainWindow() {
88     delete history;
89 }
90
91 bool MainWindow::eventFilter(QObject *obj, QEvent *event) {
92     if (event->type() == QEvent::ToolTip) {
93         // kill tooltips
94         return true;
95     } else {
96         // standard event processing
97         return QObject::eventFilter(obj, event);
98     }
99 }
100
101 void MainWindow::createActions() {
102
103     QMap<QString, QAction*> *actions = The::globalActions();
104
105     stopAct = new QAction(QtIconLoader::icon("media-playback-stop"), tr("&Stop"), this);
106     stopAct->setStatusTip(tr("Stop playback and go back to the search view"));
107     stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
108     stopAct->setEnabled(false);
109     actions->insert("stop", stopAct);
110     connect(stopAct, SIGNAL(triggered()), this, SLOT(stop()));
111
112     skipAct = new QAction(QtIconLoader::icon("media-skip-forward"), tr("S&kip"), this);
113     skipAct->setStatusTip(tr("Skip to the next video"));
114     skipAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_Right) << QKeySequence(Qt::Key_MediaNext));
115     skipAct->setEnabled(false);
116     actions->insert("skip", skipAct);
117     connect(skipAct, SIGNAL(triggered()), mediaView, SLOT(skip()));
118
119     pauseAct = new QAction(QtIconLoader::icon("media-playback-pause"), tr("&Pause"), this);
120     pauseAct->setStatusTip(tr("Pause playback"));
121     pauseAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Space) << QKeySequence(Qt::Key_MediaPlay));
122     pauseAct->setEnabled(false);
123     actions->insert("pause", pauseAct);
124     connect(pauseAct, SIGNAL(triggered()), mediaView, SLOT(pause()));
125
126     fullscreenAct = new QAction(QtIconLoader::icon("view-fullscreen"), tr("&Full Screen"), this);
127     fullscreenAct->setStatusTip(tr("Go full screen"));
128     fullscreenAct->setShortcut(QKeySequence(Qt::ALT + Qt::Key_Return));
129     fullscreenAct->setShortcutContext(Qt::ApplicationShortcut);
130 #if QT_VERSION >= 0x040600
131     fullscreenAct->setPriority(QAction::LowPriority);
132 #endif
133     actions->insert("fullscreen", fullscreenAct);
134     connect(fullscreenAct, SIGNAL(triggered()), this, SLOT(fullscreen()));
135
136     compactViewAct = new QAction(tr("&Compact mode"), this);
137     compactViewAct->setStatusTip(tr("Hide the playlist and the toolbar"));
138     compactViewAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Return));
139     compactViewAct->setCheckable(true);
140     compactViewAct->setChecked(false);
141     compactViewAct->setEnabled(false);
142     actions->insert("compactView", compactViewAct);
143     connect(compactViewAct, SIGNAL(toggled(bool)), this, SLOT(compactView(bool)));
144
145     webPageAct = new QAction(tr("Open the &YouTube page"), this);
146     webPageAct->setStatusTip(tr("Go to the YouTube video page and pause playback"));
147     webPageAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Y));
148     webPageAct->setEnabled(false);
149     actions->insert("webpage", webPageAct);
150     connect(webPageAct, SIGNAL(triggered()), mediaView, SLOT(openWebPage()));
151
152     copyPageAct = new QAction(tr("Copy the YouTube &link"), this);
153     copyPageAct->setStatusTip(tr("Copy the current video YouTube link to the clipboard"));
154     copyPageAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_L));
155     copyPageAct->setEnabled(false);
156     actions->insert("pagelink", copyPageAct);
157     connect(copyPageAct, SIGNAL(triggered()), mediaView, SLOT(copyWebPage()));
158
159     copyLinkAct = new QAction(tr("Copy the video stream &URL"), this);
160     copyLinkAct->setStatusTip(tr("Copy the current video stream URL to the clipboard"));
161     copyLinkAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_U));
162     copyLinkAct->setEnabled(false);
163     actions->insert("videolink", copyLinkAct);
164     connect(copyLinkAct, SIGNAL(triggered()), mediaView, SLOT(copyVideoLink()));
165
166     removeAct = new QAction(tr("&Remove"), this);
167     removeAct->setStatusTip(tr("Remove the selected videos from the playlist"));
168     removeAct->setShortcuts(QList<QKeySequence>() << QKeySequence("Del") << QKeySequence("Backspace"));
169     removeAct->setEnabled(false);
170     actions->insert("remove", removeAct);
171     connect(removeAct, SIGNAL(triggered()), mediaView, SLOT(removeSelected()));
172
173     moveUpAct = new QAction(tr("Move &Up"), this);
174     moveUpAct->setStatusTip(tr("Move up the selected videos in the playlist"));
175     moveUpAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Up));
176     moveUpAct->setEnabled(false);
177     actions->insert("moveUp", moveUpAct);
178     connect(moveUpAct, SIGNAL(triggered()), mediaView, SLOT(moveUpSelected()));
179
180     moveDownAct = new QAction(tr("Move &Down"), this);
181     moveDownAct->setStatusTip(tr("Move down the selected videos in the playlist"));
182     moveDownAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Down));
183     moveDownAct->setEnabled(false);
184     actions->insert("moveDown", moveDownAct);
185     connect(moveDownAct, SIGNAL(triggered()), mediaView, SLOT(moveDownSelected()));
186
187     clearAct = new QAction(tr("&Clear recent keywords"), this);
188     clearAct->setMenuRole(QAction::ApplicationSpecificRole);
189     clearAct->setShortcuts(QList<QKeySequence>()
190                            << QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Delete)
191                            << QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Backspace));
192     clearAct->setStatusTip(tr("Clear the search history. Cannot be undone."));
193     clearAct->setEnabled(true);
194     actions->insert("clearRecentKeywords", clearAct);
195     connect(clearAct, SIGNAL(triggered()), SLOT(clearRecentKeywords()));
196
197     quitAct = new QAction(tr("&Quit"), this);
198     quitAct->setMenuRole(QAction::QuitRole);
199     quitAct->setShortcuts(QList<QKeySequence>() << QKeySequence(tr("Ctrl+Q")) << QKeySequence(Qt::CTRL + Qt::Key_W));
200     quitAct->setStatusTip(tr("Bye"));
201     actions->insert("quit", quitAct);
202     connect(quitAct, SIGNAL(triggered()), this, SLOT(close()));
203
204     siteAct = new QAction(tr("&Website"), this);
205     siteAct->setShortcut(QKeySequence::HelpContents);
206     siteAct->setStatusTip(tr("%1 on the Web").arg(Constants::APP_NAME));
207     actions->insert("site", siteAct);
208     connect(siteAct, SIGNAL(triggered()), this, SLOT(visitSite()));
209
210     donateAct = new QAction(tr("Make a &donation"), this);
211     donateAct->setStatusTip(tr("Please support the continued development of %1").arg(Constants::APP_NAME));
212     actions->insert("donate", donateAct);
213     connect(donateAct, SIGNAL(triggered()), this, SLOT(donate()));
214
215     aboutAct = new QAction(tr("&About"), this);
216     aboutAct->setMenuRole(QAction::AboutRole);
217     aboutAct->setStatusTip(tr("Info about %1").arg(Constants::APP_NAME));
218     actions->insert("about", aboutAct);
219     connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
220
221     // Invisible actions
222
223     searchFocusAct = new QAction(this);
224     searchFocusAct->setShortcut(QKeySequence::Find);
225     searchFocusAct->setStatusTip(tr("Search"));
226     actions->insert("search", searchFocusAct);
227     connect(searchFocusAct, SIGNAL(triggered()), this, SLOT(searchFocus()));
228     addAction(searchFocusAct);
229
230     volumeUpAct = new QAction(this);
231     volumeUpAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_Plus) << QKeySequence(Qt::Key_VolumeUp));
232     actions->insert("volume-up", volumeUpAct);
233     connect(volumeUpAct, SIGNAL(triggered()), this, SLOT(volumeUp()));
234     addAction(volumeUpAct);
235
236     volumeDownAct = new QAction(this);
237     volumeDownAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_Minus) << QKeySequence(Qt::Key_VolumeDown));
238     actions->insert("volume-down", volumeDownAct);
239     connect(volumeDownAct, SIGNAL(triggered()), this, SLOT(volumeDown()));
240     addAction(volumeDownAct);
241
242     volumeMuteAct = new QAction(this);
243     volumeMuteAct->setIcon(QtIconLoader::icon("audio-volume-high"));
244     volumeMuteAct->setStatusTip(tr("Mute volume"));
245     volumeMuteAct->setShortcuts(QList<QKeySequence>()
246                                 << QKeySequence(tr("Ctrl+M"))
247                                 << QKeySequence(Qt::Key_VolumeMute));
248     actions->insert("volume-mute", volumeMuteAct);
249     connect(volumeMuteAct, SIGNAL(triggered()), SLOT(volumeMute()));
250     addAction(volumeMuteAct);
251
252     QAction *definitionAct = new QAction(this);
253     definitionAct->setIcon(QtIconLoader::icon("video-display"));
254     definitionAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_D));
255     /*
256     QMenu *definitionMenu = new QMenu(this);
257     foreach (QString definition, VideoDefinition::getDefinitionNames()) {
258         definitionMenu->addAction(definition);
259     }
260     definitionAct->setMenu(definitionMenu);
261     */
262     actions->insert("definition", definitionAct);
263     connect(definitionAct, SIGNAL(triggered()), SLOT(toggleDefinitionMode()));
264     addAction(definitionAct);
265
266     QAction *action;
267
268     /*
269     action = new QAction(tr("&Autoplay"), this);
270     action->setStatusTip(tr("Automatically start playing videos"));
271     action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_P));
272     action->setCheckable(true);
273     connect(action, SIGNAL(toggled(bool)), SLOT(setAutoplay(bool)));
274     actions->insert("autoplay", action);
275     */
276
277     action = new QAction(tr("&Downloads"), this);
278     action->setStatusTip(tr("Show details about video downloads"));
279     action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_J));
280     action->setCheckable(true);
281     action->setIcon(QtIconLoader::icon("go-down"));
282     action->setVisible(false);
283     connect(action, SIGNAL(toggled(bool)), SLOT(toggleDownloads(bool)));
284     actions->insert("downloads", action);
285
286     action = new QAction(tr("&Download"), this);
287     action->setStatusTip(tr("Download the current video"));
288     action->setShortcut(QKeySequence::Save);
289     action->setIcon(QtIconLoader::icon("go-down"));
290     action->setEnabled(false);
291 #if QT_VERSION >= 0x040600
292     action->setPriority(QAction::LowPriority);
293 #endif
294     connect(action, SIGNAL(triggered()), mediaView, SLOT(downloadVideo()));
295     actions->insert("download", action);
296
297     // common action properties
298     foreach (QAction *action, actions->values()) {
299
300         // add actions to the MainWindow so that they work
301         // when the menu is hidden
302         addAction(action);
303
304         // never autorepeat.
305         // unexperienced users tend to keep keys pressed for a "long" time
306         action->setAutoRepeat(false);
307
308         // set to something more meaningful then the toolbar text
309         // HELP! how to remove tooltips altogether?!
310         if (!action->statusTip().isEmpty())
311             action->setToolTip(action->statusTip());
312
313         // show keyboard shortcuts in the status bar
314         if (!action->shortcut().isEmpty())
315             action->setStatusTip(action->statusTip() + " (" + action->shortcut().toString(QKeySequence::NativeText) + ")");
316
317         // no icons in menus
318         action->setIconVisibleInMenu(false);
319
320     }
321
322 }
323
324 void MainWindow::createMenus() {
325
326     QMap<QString, QMenu*> *menus = The::globalMenus();
327
328     fileMenu = menuBar()->addMenu(tr("&Application"));
329     // menus->insert("file", fileMenu);
330     fileMenu->addAction(clearAct);
331 #ifndef APP_MAC
332     fileMenu->addSeparator();
333 #endif
334     fileMenu->addAction(quitAct);
335
336     playlistMenu = menuBar()->addMenu(tr("&Playlist"));
337     menus->insert("playlist", playlistMenu);
338     playlistMenu->addAction(removeAct);
339     playlistMenu->addSeparator();
340     playlistMenu->addAction(moveUpAct);
341     playlistMenu->addAction(moveDownAct);
342
343     viewMenu = menuBar()->addMenu(tr("&Video"));
344     menus->insert("video", viewMenu);
345     viewMenu->addAction(stopAct);
346     viewMenu->addAction(pauseAct);
347     viewMenu->addAction(skipAct);
348     viewMenu->addSeparator();
349     viewMenu->addAction(The::globalActions()->value("download"));
350     viewMenu->addSeparator();
351     viewMenu->addAction(webPageAct);
352     viewMenu->addAction(copyPageAct);
353     viewMenu->addAction(copyLinkAct);
354     viewMenu->addSeparator();
355     viewMenu->addAction(compactViewAct);
356     viewMenu->addAction(fullscreenAct);
357 #ifdef APP_MAC
358     extern void qt_mac_set_dock_menu(QMenu *);
359     qt_mac_set_dock_menu(viewMenu);
360 #endif
361
362     helpMenu = menuBar()->addMenu(tr("&Help"));
363     helpMenu->addAction(siteAct);
364 #if !defined(APP_MAC) && !defined(APP_WIN)
365     helpMenu->addAction(donateAct);
366 #endif
367     helpMenu->addAction(aboutAct);
368 }
369
370 void MainWindow::createToolBars() {
371
372     setUnifiedTitleAndToolBarOnMac(true);
373
374     mainToolBar = new QToolBar(this);
375 #if QT_VERSION < 0x040600 | defined(APP_MAC)
376     mainToolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
377 #elif defined(APP_WIN)
378     mainToolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
379     mainToolBar->setStyleSheet(
380             "QToolBar {"
381                 "background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #fafcfd, stop:.5 #e6f0fa, stop:.51 #dde9f7, stop:1 #dde9f7);"
382                 "border: 0;"
383                 "border-bottom: 1px solid #a0afc3;"
384             "}");
385 #else
386     mainToolBar->setToolButtonStyle(Qt::ToolButtonFollowStyle);
387 #endif
388     mainToolBar->setFloatable(false);
389     mainToolBar->setMovable(false);
390
391 #if defined(APP_MAC) | defined(APP_WIN)
392     mainToolBar->setIconSize(QSize(32, 32));
393 #endif
394
395     mainToolBar->addAction(stopAct);
396     mainToolBar->addAction(pauseAct);
397     mainToolBar->addAction(skipAct);
398     mainToolBar->addAction(fullscreenAct);
399     mainToolBar->addAction(The::globalActions()->value("download"));
400
401     mainToolBar->addWidget(new Spacer());
402
403     QFont smallerFont = FontUtils::small();
404     currentTime = new QLabel(mainToolBar);
405     currentTime->setFont(smallerFont);
406     mainToolBar->addWidget(currentTime);
407
408     mainToolBar->addWidget(new Spacer());
409
410     seekSlider = new Phonon::SeekSlider(this);
411     seekSlider->setIconVisible(false);
412     seekSlider->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
413     mainToolBar->addWidget(seekSlider);
414
415 /*
416     mainToolBar->addWidget(new Spacer());
417     slider = new QSlider(this);
418     slider->setOrientation(Qt::Horizontal);
419     slider->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
420     mainToolBar->addWidget(slider);
421 */
422
423     mainToolBar->addWidget(new Spacer());
424
425     totalTime = new QLabel(mainToolBar);
426     totalTime->setFont(smallerFont);
427     mainToolBar->addWidget(totalTime);
428
429     mainToolBar->addWidget(new Spacer());
430
431     mainToolBar->addAction(volumeMuteAct);
432
433     volumeSlider = new Phonon::VolumeSlider(this);
434     volumeSlider->setMuteVisible(false);
435     // qDebug() << volumeSlider->children();
436     // status tip for the volume slider
437     QSlider* volumeQSlider = volumeSlider->findChild<QSlider*>();
438     if (volumeQSlider)
439         volumeQSlider->setStatusTip(tr("Press %1 to raise the volume, %2 to lower it").arg(
440                 volumeUpAct->shortcut().toString(QKeySequence::NativeText), volumeDownAct->shortcut().toString(QKeySequence::NativeText)));
441     // this makes the volume slider smaller
442     volumeSlider->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
443     mainToolBar->addWidget(volumeSlider);
444
445     mainToolBar->addWidget(new Spacer());
446
447     toolbarSearch->setStatusTip(searchFocusAct->statusTip());
448     mainToolBar->addWidget(toolbarSearch);
449
450     mainToolBar->addWidget(new Spacer());
451
452     addToolBar(mainToolBar);
453 }
454
455 void MainWindow::createStatusBar() {
456
457     // remove ugly borders on OSX
458     // also remove excessive spacing
459     statusBar()->setStyleSheet("::item{border:0 solid} QToolBar {padding:0;spacing:0;margin:0;border:0}");
460
461     QToolBar *toolBar = new QToolBar(this);
462     toolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
463     toolBar->setIconSize(QSize(16, 16));
464     toolBar->addAction(The::globalActions()->value("downloads"));
465     // toolBar->addAction(The::globalActions()->value("autoplay"));
466     toolBar->addAction(The::globalActions()->value("definition"));
467     statusBar()->addPermanentWidget(toolBar);
468
469     statusBar()->show();
470 }
471
472 void MainWindow::readSettings() {
473     QSettings settings;
474     restoreGeometry(settings.value("geometry").toByteArray());
475 #ifdef APP_MAC
476     if (!isMaximized())
477         move(x(), y() + mainToolBar->height() + 8);
478 #endif
479     setDefinitionMode(settings.value("definition", VideoDefinition::getDefinitionNames().first()).toString());
480     audioOutput->setVolume(settings.value("volume", 1).toDouble());
481     audioOutput->setMuted(settings.value("volumeMute").toBool());
482 }
483
484 void MainWindow::writeSettings() {
485
486     QSettings settings;
487
488     // do not save geometry when in full screen
489     if (!m_fullscreen) {
490         settings.setValue("geometry", saveGeometry());
491     }
492
493     settings.setValue("volume", audioOutput->volume());
494     settings.setValue("volumeMute", audioOutput->isMuted());
495     mediaView->saveSplitterState();
496 }
497
498 void MainWindow::goBack() {
499     if ( history->size() > 1 ) {
500         history->pop();
501         QWidget *widget = history->pop();
502         showWidget(widget);
503     }
504 }
505
506 void MainWindow::showWidget ( QWidget* widget ) {
507
508     setUpdatesEnabled(false);
509
510     // call hide method on the current view
511     View* oldView = dynamic_cast<View *> (views->currentWidget());
512     if (oldView) {
513         oldView->disappear();
514     }
515
516     // call show method on the new view
517     View* newView = dynamic_cast<View *> (widget);
518     if (newView) {
519         newView->appear();
520         QMap<QString,QVariant> metadata = newView->metadata();
521         QString windowTitle = metadata.value("title").toString();
522         if (windowTitle.length())
523             windowTitle += " - ";
524         setWindowTitle(windowTitle + Constants::APP_NAME);
525         statusBar()->showMessage((metadata.value("description").toString()));
526     }
527
528     stopAct->setEnabled(widget == mediaView);
529     fullscreenAct->setEnabled(widget == mediaView);
530     compactViewAct->setEnabled(widget == mediaView);
531     webPageAct->setEnabled(widget == mediaView);
532     copyPageAct->setEnabled(widget == mediaView);
533     copyLinkAct->setEnabled(widget == mediaView);
534     aboutAct->setEnabled(widget != aboutView);
535     The::globalActions()->value("download")->setEnabled(widget == mediaView);
536     The::globalActions()->value("downloads")->setChecked(widget == downloadView);
537
538     // toolbar only for the mediaView
539     /* mainToolBar->setVisible(
540             (widget == mediaView && !compactViewAct->isChecked())
541             || widget == downloadView
542             ); */
543
544     setUpdatesEnabled(true);
545
546     QWidget *oldWidget = views->currentWidget();
547     views->setCurrentWidget(widget);
548
549 #ifdef APP_MAC
550     // crossfade only on OSX
551     // where we can be sure of video performance
552     fadeInWidget(oldWidget, widget);
553 #endif
554
555     history->push(widget);
556 }
557
558 void MainWindow::fadeInWidget(QWidget *oldWidget, QWidget *newWidget) {
559     if (faderWidget) faderWidget->close();
560     if (!oldWidget || !newWidget) {
561         // qDebug() << "no widgets";
562         return;
563     }
564     faderWidget = new FaderWidget(newWidget);
565     faderWidget->start(QPixmap::grabWidget(oldWidget));
566 }
567
568 void MainWindow::about() {
569     if (!aboutView) {
570         aboutView = new AboutView(this);
571         views->addWidget(aboutView);
572     }
573     showWidget(aboutView);
574 }
575
576 void MainWindow::visitSite() {
577     QUrl url(Constants::WEBSITE);
578     statusBar()->showMessage(QString(tr("Opening %1").arg(url.toString())));
579     QDesktopServices::openUrl(url);
580 }
581
582 void MainWindow::donate() {
583     QUrl url(QString(Constants::WEBSITE) + "#donate");
584     statusBar()->showMessage(QString(tr("Opening %1").arg(url.toString())));
585     QDesktopServices::openUrl(url);
586 }
587
588 void MainWindow::quit() {
589     writeSettings();
590     qApp->quit();
591 }
592
593 void MainWindow::closeEvent(QCloseEvent *event) {
594     if (DownloadManager::instance()->activeItems() > 0) {
595         QMessageBox msgBox;
596         msgBox.setIconPixmap(QPixmap(":/images/app.png").scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation));
597         msgBox.setText(tr("Do you want to exit %1 with a download in progress?").arg(Constants::APP_NAME));
598         msgBox.setInformativeText(tr("If you close %1 now, this download will be cancelled.").arg(Constants::APP_NAME));
599         msgBox.setModal(true);
600
601         msgBox.addButton(tr("Close and cancel download"), QMessageBox::RejectRole);
602         QPushButton *waitButton = msgBox.addButton(tr("Wait for download to finish"), QMessageBox::ActionRole);
603
604         msgBox.exec();
605
606         if (msgBox.clickedButton() == waitButton) {
607             event->ignore();
608             return;
609         }
610
611     }
612     quit();
613     QWidget::closeEvent(event);
614 }
615
616 void MainWindow::showSearch() {
617     showWidget(searchView);
618     currentTime->clear();
619     totalTime->clear();
620 }
621
622 void MainWindow::showMedia(SearchParams *searchParams) {
623     mediaView->search(searchParams);
624     showWidget(mediaView);
625 }
626
627 void MainWindow::stateChanged(Phonon::State newState, Phonon::State /* oldState */) {
628
629     // qDebug() << "Phonon state: " << newState;
630
631     switch (newState) {
632
633     case Phonon::ErrorState:
634         if (mediaObject->errorType() == Phonon::FatalError) {
635             statusBar()->showMessage(tr("Fatal error: %1").arg(mediaObject->errorString()));
636         } else {
637             statusBar()->showMessage(tr("Error: %1").arg(mediaObject->errorString()));
638         }
639         break;
640
641          case Phonon::PlayingState:
642         pauseAct->setEnabled(true);
643         pauseAct->setIcon(QtIconLoader::icon("media-playback-pause"));
644         pauseAct->setText(tr("&Pause"));
645         pauseAct->setStatusTip(tr("Pause playback") + " (" +  pauseAct->shortcut().toString(QKeySequence::NativeText) + ")");
646         skipAct->setEnabled(true);
647         // stopAct->setEnabled(true);
648         break;
649
650          case Phonon::StoppedState:
651         pauseAct->setEnabled(false);
652         skipAct->setEnabled(false);
653         // stopAct->setEnabled(false);
654         break;
655
656          case Phonon::PausedState:
657         skipAct->setEnabled(true);
658         pauseAct->setEnabled(true);
659         pauseAct->setIcon(QtIconLoader::icon("media-playback-start"));
660         pauseAct->setText(tr("&Play"));
661         pauseAct->setStatusTip(tr("Resume playback") + " (" +  pauseAct->shortcut().toString(QKeySequence::NativeText) + ")");
662         // stopAct->setEnabled(true);
663         break;
664
665          case Phonon::BufferingState:
666          case Phonon::LoadingState:
667         skipAct->setEnabled(true);
668         pauseAct->setEnabled(false);
669         currentTime->clear();
670         totalTime->clear();
671         // stopAct->setEnabled(true);
672         break;
673
674          default:
675         ;
676     }
677 }
678
679 void MainWindow::stop() {
680     mediaView->stop();
681     showSearch();
682 }
683
684 void MainWindow::fullscreen() {
685
686     // No compact view action when in full screen
687     compactViewAct->setVisible(m_fullscreen);
688     compactViewAct->setChecked(false);
689
690     // Also no Youtube action since it opens a new window
691     webPageAct->setVisible(m_fullscreen);
692     copyPageAct->setVisible(m_fullscreen);
693     copyLinkAct->setVisible(m_fullscreen);
694
695     stopAct->setVisible(m_fullscreen);
696
697     // workaround: prevent focus on the search bar
698     // it steals the Space key needed for Play/Pause
699     toolbarSearch->setEnabled(m_fullscreen);
700
701     // Hide anything but the video
702     mediaView->setPlaylistVisible(m_fullscreen);
703     statusBar()->setVisible(m_fullscreen);
704
705 #ifndef APP_MAC
706     menuBar()->setVisible(m_fullscreen);
707 #endif
708
709 #ifdef APP_MAC
710     // make the actions work when video is fullscreen (on the Mac)
711     QMap<QString, QAction*> *actions = The::globalActions();
712     foreach (QAction *action, actions->values()) {
713         if (m_fullscreen) {
714             action->setShortcutContext(Qt::WindowShortcut);
715         } else {
716             action->setShortcutContext(Qt::ApplicationShortcut);
717         }
718     }
719 #endif
720
721     if (m_fullscreen) {
722
723         // Exit full screen
724
725         // use setShortcuts instead of setShortcut
726         // the latter seems not to work
727         fullscreenAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::ALT + Qt::Key_Return));
728         fullscreenAct->setText(tr("&Full Screen"));
729         stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
730
731 #ifdef APP_MAC
732         setCentralWidget(views);
733         views->showNormal();
734         show();
735         mediaView->setFocus();
736 #else
737         mainToolBar->show();
738         if (m_maximized) showMaximized();
739         else showNormal();
740 #endif
741
742         // Make sure the window has focus
743         activateWindow();
744
745     } else {
746
747         // Enter full screen
748
749         stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_MediaStop));
750         fullscreenAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::ALT + Qt::Key_Return));
751         fullscreenAct->setText(tr("Exit &Full Screen"));
752         m_maximized = isMaximized();
753
754         // save geometry now, if the user quits when in full screen
755         // geometry won't be saved
756         writeSettings();
757
758 #ifdef APP_MAC
759         hide();
760         views->setParent(0);
761         QTimer::singleShot(0, views, SLOT(showFullScreen()));
762 #else
763         mainToolBar->hide();
764         showFullScreen();
765 #endif
766
767     }
768
769     m_fullscreen = !m_fullscreen;
770
771 }
772
773 void MainWindow::compactView(bool enable) {
774
775     mediaView->setPlaylistVisible(!enable);
776     statusBar()->setVisible(!enable);
777
778 #ifndef APP_MAC
779     menuBar()->setVisible(!enable);
780 #endif
781
782     if (enable) {
783         stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_MediaStop));
784         compactViewAct->setShortcuts(
785                 QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_Return)
786                 << QKeySequence(Qt::Key_Escape));
787
788         // ensure focus does not end up to the search box
789         // as it would steal the Space shortcut
790         mediaView->setFocus();
791     } else {
792         compactViewAct->setShortcuts(QList<QKeySequence>() <<  QKeySequence(Qt::CTRL + Qt::Key_Return));
793         stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
794     }
795
796 }
797
798 void MainWindow::searchFocus() {
799     QWidget *view = views->currentWidget();
800     if (view == mediaView) {
801         toolbarSearch->selectAll();
802         toolbarSearch->setFocus();
803     }
804 }
805
806 void MainWindow::initPhonon() {
807     // Phonon initialization
808     if (mediaObject) delete mediaObject;
809     if (audioOutput) delete audioOutput;
810     mediaObject = new Phonon::MediaObject(this);
811     mediaObject->setTickInterval(100);
812     connect(mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
813             this, SLOT(stateChanged(Phonon::State, Phonon::State)));
814     connect(mediaObject, SIGNAL(tick(qint64)), this, SLOT(tick(qint64)));
815     connect(mediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64)));
816     seekSlider->setMediaObject(mediaObject);
817     audioOutput = new Phonon::AudioOutput(Phonon::VideoCategory, this);
818     connect(audioOutput, SIGNAL(volumeChanged(qreal)), this, SLOT(volumeChanged(qreal)));
819     connect(audioOutput, SIGNAL(mutedChanged(bool)), this, SLOT(volumeMutedChanged(bool)));
820     volumeSlider->setAudioOutput(audioOutput);
821     Phonon::createPath(mediaObject, audioOutput);
822 }
823
824 void MainWindow::tick(qint64 time) {
825     if (time <= 0) {
826         currentTime->clear();
827         return;
828     }
829
830     currentTime->setText(formatTime(time));
831
832     // remaining time
833     const qint64 remainingTime = mediaObject->remainingTime();
834     currentTime->setStatusTip(tr("Remaining time: %1").arg(formatTime(remainingTime)));
835
836     /*
837     slider->blockSignals(true);
838     slider->setValue(time/1000);
839     slider->blockSignals(false);
840     */
841 }
842
843 void MainWindow::totalTimeChanged(qint64 time) {
844     if (time <= 0) {
845         totalTime->clear();
846         return;
847     }
848     totalTime->setText(formatTime(time));
849
850     /*
851     slider->blockSignals(true);
852     slider->setMaximum(time/1000);
853     slider->blockSignals(false);
854     */
855
856 }
857
858 QString MainWindow::formatTime(qint64 time) {
859     QTime displayTime;
860     displayTime = displayTime.addMSecs(time);
861     QString timeString;
862     // 60 * 60 * 1000 = 3600000
863     if (time > 3600000)
864         timeString = displayTime.toString("h:mm:ss");
865     else
866         timeString = displayTime.toString("m:ss");
867     return timeString;
868 }
869
870 void MainWindow::volumeUp() {
871     qreal newVolume = volumeSlider->audioOutput()->volume() + .1;
872     if (newVolume > volumeSlider->maximumVolume())
873         newVolume = volumeSlider->maximumVolume();
874     volumeSlider->audioOutput()->setVolume(newVolume);
875 }
876
877 void MainWindow::volumeDown() {
878     qreal newVolume = volumeSlider->audioOutput()->volume() - .1;
879     if (newVolume < 0)
880         newVolume = 0;
881     volumeSlider->audioOutput()->setVolume(newVolume);
882 }
883
884 void MainWindow::volumeMute() {
885     volumeSlider->audioOutput()->setMuted(!volumeSlider->audioOutput()->isMuted());
886 }
887
888 void MainWindow::volumeChanged(qreal newVolume) {
889     // automatically unmute when volume changes
890     if (volumeSlider->audioOutput()->isMuted())
891         volumeSlider->audioOutput()->setMuted(false);
892     statusBar()->showMessage(tr("Volume at %1%").arg(newVolume*100));
893 }
894
895 void MainWindow::volumeMutedChanged(bool muted) {
896     if (muted) {
897         volumeMuteAct->setIcon(QtIconLoader::icon("audio-volume-muted"));
898         statusBar()->showMessage(tr("Volume is muted"));
899     } else {
900         volumeMuteAct->setIcon(QtIconLoader::icon("audio-volume-high"));
901         statusBar()->showMessage(tr("Volume is unmuted"));
902     }
903 }
904
905 void MainWindow::setDefinitionMode(QString definitionName) {
906     QAction *definitionAct = The::globalActions()->value("definition");
907     definitionAct->setText(definitionName);
908     definitionAct->setStatusTip(tr("Maximum video definition set to %1").arg(definitionAct->text())
909                                 + " (" +  definitionAct->shortcut().toString(QKeySequence::NativeText) + ")");
910     statusBar()->showMessage(definitionAct->statusTip());
911     QSettings settings;
912     settings.setValue("definition", definitionName);
913 }
914
915 void MainWindow::toggleDefinitionMode() {
916     QSettings settings;
917     QString currentDefinition = settings.value("definition").toString();
918     QStringList definitionNames = VideoDefinition::getDefinitionNames();
919     int currentIndex = definitionNames.indexOf(currentDefinition);
920     int nextIndex = 0;
921     if (currentIndex != definitionNames.size() - 1) {
922         nextIndex = currentIndex + 1;
923     }
924     QString nextDefinition = definitionNames.at(nextIndex);
925     setDefinitionMode(nextDefinition);
926 }
927
928 void MainWindow::showFullscreenToolbar(bool show) {
929     if (!m_fullscreen) return;
930     mainToolBar->setVisible(show);
931 }
932
933 void MainWindow::showFullscreenPlaylist(bool show) {
934     if (!m_fullscreen) return;
935     mediaView->setPlaylistVisible(show);
936 }
937
938 void MainWindow::clearRecentKeywords() {
939     QSettings settings;
940     settings.remove("recentKeywords");
941     searchView->updateRecentKeywords();
942     statusBar()->showMessage(tr("Your privacy is now safe"));
943 }
944
945 /*
946  void MainWindow::setAutoplay(bool enabled) {
947      QSettings settings;
948      settings.setValue("autoplay", QVariant::fromValue(enabled));
949  }
950  */
951
952 void MainWindow::updateDownloadMessage(QString message) {
953     The::globalActions()->value("downloads")->setText(message);
954 }
955
956 void MainWindow::downloadsFinished() {
957     The::globalActions()->value("downloads")->setText(tr("&Downloads"));
958     statusBar()->showMessage(tr("Downloads complete"));
959 }
960
961 void MainWindow::toggleDownloads(bool show) {
962
963     if (show) {
964         stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_MediaStop));
965         The::globalActions()->value("downloads")->setShortcuts(
966                 QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_J)
967                 << QKeySequence(Qt::Key_Escape));
968     } else {
969         The::globalActions()->value("downloads")->setShortcuts(
970                 QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_J));
971         stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
972     }
973
974     if (!downloadView) {
975         downloadView = new DownloadView(this);
976         views->addWidget(downloadView);
977     }
978     if (show) showWidget(downloadView);
979     else goBack();
980 }
981
982 void MainWindow::startToolbarSearch(QString query) {
983
984     query = query.trimmed();
985
986     // check for empty query
987     if (query.length() == 0) {
988         return;
989     }
990
991     SearchParams *searchParams = new SearchParams();
992     searchParams->setKeywords(query);
993
994     // go!
995     showMedia(searchParams);
996 }