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