]> git.sur5r.net Git - minitube/blob - src/MainWindow.cpp
Imported Upstream version 1.4.3
[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->setVisible(m_fullscreen);
714     toolbarSearch->setEnabled(m_fullscreen);
715
716     // Hide anything but the video
717     mediaView->setPlaylistVisible(m_fullscreen);
718     statusBar()->setVisible(m_fullscreen);
719
720 #ifndef APP_MAC
721     menuBar()->setVisible(m_fullscreen);
722 #endif
723
724 #ifdef APP_MAC
725     // make the actions work when video is fullscreen (on the Mac)
726     QMap<QString, QAction*> *actions = The::globalActions();
727     foreach (QAction *action, actions->values()) {
728         if (m_fullscreen) {
729             action->setShortcutContext(Qt::WindowShortcut);
730         } else {
731             action->setShortcutContext(Qt::ApplicationShortcut);
732         }
733     }
734 #endif
735
736     if (m_fullscreen) {
737
738         // Exit full screen
739
740         // use setShortcuts instead of setShortcut
741         // the latter seems not to work
742         fullscreenAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::ALT + Qt::Key_Return));
743         fullscreenAct->setText(tr("&Full Screen"));
744         stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
745
746 #ifdef APP_MAC
747         setCentralWidget(views);
748         views->showNormal();
749         show();
750         mediaView->setFocus();
751 #else
752         mainToolBar->show();
753         if (m_maximized) showMaximized();
754         else showNormal();
755 #endif
756
757         // Make sure the window has focus
758         activateWindow();
759
760     } else {
761
762         // Enter full screen
763
764         stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_MediaStop));
765         fullscreenAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::ALT + Qt::Key_Return));
766         fullscreenAct->setText(tr("Exit &Full Screen"));
767         m_maximized = isMaximized();
768
769         // save geometry now, if the user quits when in full screen
770         // geometry won't be saved
771         writeSettings();
772
773 #ifdef APP_MAC
774         hide();
775         views->setParent(0);
776         QTimer::singleShot(0, views, SLOT(showFullScreen()));
777 #else
778         mainToolBar->hide();
779         showFullScreen();
780 #endif
781
782     }
783
784     m_fullscreen = !m_fullscreen;
785
786 }
787
788 void MainWindow::compactView(bool enable) {
789
790     mediaView->setPlaylistVisible(!enable);
791     statusBar()->setVisible(!enable);
792
793 #ifndef APP_MAC
794     menuBar()->setVisible(!enable);
795 #endif
796
797     if (enable) {
798         stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_MediaStop));
799         compactViewAct->setShortcuts(
800                 QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_Return)
801                 << QKeySequence(Qt::Key_Escape));
802
803         // ensure focus does not end up to the search box
804         // as it would steal the Space shortcut
805         mediaView->setFocus();
806     } else {
807         compactViewAct->setShortcuts(QList<QKeySequence>() <<  QKeySequence(Qt::CTRL + Qt::Key_Return));
808         stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
809     }
810
811 }
812
813 void MainWindow::searchFocus() {
814     QWidget *view = views->currentWidget();
815     if (view == mediaView) {
816         toolbarSearch->selectAll();
817         toolbarSearch->setFocus();
818     }
819 }
820
821 void MainWindow::initPhonon() {
822     // Phonon initialization
823     if (mediaObject) delete mediaObject;
824     if (audioOutput) delete audioOutput;
825     mediaObject = new Phonon::MediaObject(this);
826     mediaObject->setTickInterval(100);
827     connect(mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
828             this, SLOT(stateChanged(Phonon::State, Phonon::State)));
829     connect(mediaObject, SIGNAL(tick(qint64)), this, SLOT(tick(qint64)));
830     connect(mediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64)));
831     seekSlider->setMediaObject(mediaObject);
832     audioOutput = new Phonon::AudioOutput(Phonon::VideoCategory, this);
833     connect(audioOutput, SIGNAL(volumeChanged(qreal)), this, SLOT(volumeChanged(qreal)));
834     connect(audioOutput, SIGNAL(mutedChanged(bool)), this, SLOT(volumeMutedChanged(bool)));
835     volumeSlider->setAudioOutput(audioOutput);
836     Phonon::createPath(mediaObject, audioOutput);
837 }
838
839 void MainWindow::tick(qint64 time) {
840     if (time <= 0) {
841         currentTime->clear();
842         return;
843     }
844
845     currentTime->setText(formatTime(time));
846
847     // remaining time
848     const qint64 remainingTime = mediaObject->remainingTime();
849     currentTime->setStatusTip(tr("Remaining time: %1").arg(formatTime(remainingTime)));
850
851     /*
852     slider->blockSignals(true);
853     slider->setValue(time/1000);
854     slider->blockSignals(false);
855     */
856 }
857
858 void MainWindow::totalTimeChanged(qint64 time) {
859     if (time <= 0) {
860         totalTime->clear();
861         return;
862     }
863     totalTime->setText(formatTime(time));
864
865     /*
866     slider->blockSignals(true);
867     slider->setMaximum(time/1000);
868     slider->blockSignals(false);
869     */
870
871 }
872
873 QString MainWindow::formatTime(qint64 time) {
874     QTime displayTime;
875     displayTime = displayTime.addMSecs(time);
876     QString timeString;
877     // 60 * 60 * 1000 = 3600000
878     if (time > 3600000)
879         timeString = displayTime.toString("h:mm:ss");
880     else
881         timeString = displayTime.toString("m:ss");
882     return timeString;
883 }
884
885 void MainWindow::volumeUp() {
886     qreal newVolume = volumeSlider->audioOutput()->volume() + .1;
887     if (newVolume > volumeSlider->maximumVolume())
888         newVolume = volumeSlider->maximumVolume();
889     volumeSlider->audioOutput()->setVolume(newVolume);
890 }
891
892 void MainWindow::volumeDown() {
893     qreal newVolume = volumeSlider->audioOutput()->volume() - .1;
894     if (newVolume < 0)
895         newVolume = 0;
896     volumeSlider->audioOutput()->setVolume(newVolume);
897 }
898
899 void MainWindow::volumeMute() {
900     volumeSlider->audioOutput()->setMuted(!volumeSlider->audioOutput()->isMuted());
901 }
902
903 void MainWindow::volumeChanged(qreal newVolume) {
904     // automatically unmute when volume changes
905     if (volumeSlider->audioOutput()->isMuted())
906         volumeSlider->audioOutput()->setMuted(false);
907     statusBar()->showMessage(tr("Volume at %1%").arg((int)(newVolume*100)));
908 }
909
910 void MainWindow::volumeMutedChanged(bool muted) {
911     if (muted) {
912         volumeMuteAct->setIcon(QtIconLoader::icon("audio-volume-muted"));
913         statusBar()->showMessage(tr("Volume is muted"));
914     } else {
915         volumeMuteAct->setIcon(QtIconLoader::icon("audio-volume-high"));
916         statusBar()->showMessage(tr("Volume is unmuted"));
917     }
918 }
919
920 void MainWindow::setDefinitionMode(QString definitionName) {
921     QAction *definitionAct = The::globalActions()->value("definition");
922     definitionAct->setText(definitionName);
923     definitionAct->setStatusTip(tr("Maximum video definition set to %1").arg(definitionAct->text())
924                                 + " (" +  definitionAct->shortcut().toString(QKeySequence::NativeText) + ")");
925     statusBar()->showMessage(definitionAct->statusTip());
926     QSettings settings;
927     settings.setValue("definition", definitionName);
928 }
929
930 void MainWindow::toggleDefinitionMode() {
931     QSettings settings;
932     QString currentDefinition = settings.value("definition").toString();
933     QStringList definitionNames = VideoDefinition::getDefinitionNames();
934     int currentIndex = definitionNames.indexOf(currentDefinition);
935     int nextIndex = 0;
936     if (currentIndex != definitionNames.size() - 1) {
937         nextIndex = currentIndex + 1;
938     }
939     QString nextDefinition = definitionNames.at(nextIndex);
940     setDefinitionMode(nextDefinition);
941 }
942
943 void MainWindow::showFullscreenToolbar(bool show) {
944     if (!m_fullscreen) return;
945     mainToolBar->setVisible(show);
946     toolbarSearch->setVisible(show);
947     toolbarSearch->setEnabled(show);
948 }
949
950 void MainWindow::showFullscreenPlaylist(bool show) {
951     if (!m_fullscreen) return;
952     mediaView->setPlaylistVisible(show);
953 }
954
955 void MainWindow::clearRecentKeywords() {
956     QSettings settings;
957     settings.remove("recentKeywords");
958     settings.remove("recentChannels");
959     searchView->updateRecentKeywords();
960     searchView->updateRecentChannels();
961     statusBar()->showMessage(tr("Your privacy is now safe"));
962 }
963
964 /*
965  void MainWindow::setAutoplay(bool enabled) {
966      QSettings settings;
967      settings.setValue("autoplay", QVariant::fromValue(enabled));
968  }
969  */
970
971 void MainWindow::updateDownloadMessage(QString message) {
972     The::globalActions()->value("downloads")->setText(message);
973 }
974
975 void MainWindow::downloadsFinished() {
976     The::globalActions()->value("downloads")->setText(tr("&Downloads"));
977     statusBar()->showMessage(tr("Downloads complete"));
978 }
979
980 void MainWindow::toggleDownloads(bool show) {
981
982     if (show) {
983         stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_MediaStop));
984         The::globalActions()->value("downloads")->setShortcuts(
985                 QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_J)
986                 << QKeySequence(Qt::Key_Escape));
987     } else {
988         The::globalActions()->value("downloads")->setShortcuts(
989                 QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_J));
990         stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
991     }
992
993     if (!downloadView) {
994         downloadView = new DownloadView(this);
995         views->addWidget(downloadView);
996     }
997     if (show) showWidget(downloadView);
998     else goBack();
999 }
1000
1001 void MainWindow::startToolbarSearch(QString query) {
1002
1003     query = query.trimmed();
1004
1005     // check for empty query
1006     if (query.length() == 0) {
1007         return;
1008     }
1009
1010     SearchParams *searchParams = new SearchParams();
1011     searchParams->setKeywords(query);
1012
1013     // go!
1014     showMedia(searchParams);
1015 }