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