]> git.sur5r.net Git - minitube/blob - src/MainWindow.cpp
adf0e851942c65ddb84c65b27b7b5849c34708a5
[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 Q_WS_MAC
13 #include "mac_startup.h"
14 #include "macfullscreen.h"
15 #include "macsupport.h"
16 #include "macutils.h"
17 #endif
18 #ifndef Q_WS_X11
19 #include "extra.h"
20 #endif
21 #include "downloadmanager.h"
22 #include "youtubesuggest.h"
23 #include "updatechecker.h"
24 #ifdef APP_DEMO
25 #include "demostartupview.h"
26 #endif
27 #include "temporary.h"
28 #ifdef APP_MAC
29 #include "searchlineedit_mac.h"
30 #else
31 #include "searchlineedit.h"
32 #endif
33 #include <iostream>
34
35 static MainWindow *singleton = 0;
36
37 MainWindow* MainWindow::instance() {
38     if (!singleton) singleton = new MainWindow();
39     return singleton;
40 }
41
42 MainWindow::MainWindow() :
43         updateChecker(0),
44         aboutView(0),
45         downloadView(0),
46         mediaObject(0),
47         audioOutput(0),
48         m_fullscreen(false) {
49
50     singleton = this;
51
52     // views mechanism
53     history = new QStack<QWidget*>();
54     views = new QStackedWidget(this);
55     setCentralWidget(views);
56
57     // views
58     searchView = new SearchView(this);
59     connect(searchView, SIGNAL(search(SearchParams*)), this, SLOT(showMedia(SearchParams*)));
60     views->addWidget(searchView);
61
62     mediaView = new MediaView(this);
63     mediaView->setEnabled(false);
64     views->addWidget(mediaView);
65
66     // build ui
67     createActions();
68     createMenus();
69     createToolBars();
70     createStatusBar();
71
72     initPhonon();
73     mediaView->setSlider(seekSlider);
74     mediaView->setMediaObject(mediaObject);
75
76     // remove that useless menu/toolbar context menu
77     this->setContextMenuPolicy(Qt::NoContextMenu);
78
79     // mediaView init stuff thats needs actions
80     mediaView->initialize();
81
82     // event filter to block ugly toolbar tooltips
83     qApp->installEventFilter(this);
84
85     setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
86
87     // restore window position
88     readSettings();
89
90     // fix stacked widget minimum size
91     for (int i = 0; i < views->count(); i++) {
92         QWidget* view = views->widget(i);
93         if (view) view->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
94     }
95     setMinimumWidth(0);
96
97     // show the initial view
98 #ifdef APP_DEMO
99         QWidget *demoStartupView = new DemoStartupView(this);
100         views->addWidget(demoStartupView);
101         showWidget(demoStartupView);
102 #else
103     showSearch();
104 #endif
105
106     // Global shortcuts
107     GlobalShortcuts &shortcuts = GlobalShortcuts::instance();
108 #ifdef Q_WS_X11
109     if (GnomeGlobalShortcutBackend::IsGsdAvailable())
110         shortcuts.setBackend(new GnomeGlobalShortcutBackend(&shortcuts));
111 #endif
112 #ifdef Q_WS_MAC
113     mac::MacSetup();
114 #endif
115     connect(&shortcuts, SIGNAL(PlayPause()), pauseAct, SLOT(trigger()));
116     connect(&shortcuts, SIGNAL(Stop()), this, SLOT(stop()));
117     connect(&shortcuts, SIGNAL(Next()), skipAct, SLOT(trigger()));
118     connect(&shortcuts, SIGNAL(Previous()), skipBackwardAct, SLOT(trigger()));
119     // connect(&shortcuts, SIGNAL(StopAfter()), The::globalActions()->value("stopafterthis"), SLOT(toggle()));
120
121     connect(DownloadManager::instance(), SIGNAL(statusMessageChanged(QString)),
122             SLOT(updateDownloadMessage(QString)));
123     connect(DownloadManager::instance(), SIGNAL(finished()),
124             SLOT(downloadsFinished()));
125
126     setAcceptDrops(true);
127
128     mouseTimer = new QTimer(this);
129     mouseTimer->setInterval(5000);
130     mouseTimer->setSingleShot(true);
131     connect(mouseTimer, SIGNAL(timeout()), SLOT(hideMouse()));
132
133     QTimer::singleShot(0, this, SLOT(checkForUpdate()));
134
135 }
136
137 MainWindow::~MainWindow() {
138     delete history;
139 }
140
141 void MainWindow::changeEvent(QEvent* event) {
142 #ifdef APP_MAC
143     if (event->type() == QEvent::WindowStateChange) {
144         The::globalActions()->value("minimize")->setEnabled(!isMinimized());
145     }
146 #endif
147     QMainWindow::changeEvent(event);
148 }
149
150 bool MainWindow::eventFilter(QObject *obj, QEvent *event) {
151
152     if (m_fullscreen && event->type() == QEvent::MouseMove) {
153
154         QMouseEvent *mouseEvent = static_cast<QMouseEvent*> (event);
155         const int x = mouseEvent->pos().x();
156         const QString className = QString(obj->metaObject()->className());
157         const bool isHoveringVideo = (className == "QGLWidget") || (className == "VideoAreaWidget");
158
159         // qDebug() << obj << mouseEvent->pos() << isHoveringVideo << mediaView->isPlaylistVisible();
160
161         if (mediaView->isPlaylistVisible()) {
162             if (isHoveringVideo && x > 5) mediaView->setPlaylistVisible(false);
163         } else {
164             if (isHoveringVideo && x >= 0 && x < 5) mediaView->setPlaylistVisible(true);
165         }
166
167 #ifndef APP_MAC
168         const int y = mouseEvent->pos().y();
169         if (mainToolBar->isVisible()) {
170             if (isHoveringVideo && y > 5) mainToolBar->setVisible(false);
171         } else {
172             if (isHoveringVideo && y >= 0 && y < 5) mainToolBar->setVisible(true);
173         }
174 #endif
175
176         // show the normal cursor
177         unsetCursor();
178         // then hide it again after a few seconds
179         mouseTimer->start();
180
181     }
182
183     if (event->type() == QEvent::ToolTip) {
184         // kill tooltips
185         return true;
186     }
187     // standard event processing
188     return QMainWindow::eventFilter(obj, event);
189 }
190
191 void MainWindow::createActions() {
192
193     QMap<QString, QAction*> *actions = The::globalActions();
194
195     stopAct = new QAction(QtIconLoader::icon("media-playback-stop"), tr("&Stop"), this);
196     stopAct->setStatusTip(tr("Stop playback and go back to the search view"));
197     stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
198     stopAct->setEnabled(false);
199     actions->insert("stop", stopAct);
200     connect(stopAct, SIGNAL(triggered()), this, SLOT(stop()));
201
202     skipBackwardAct = new QAction(
203                 QtIconLoader::icon("media-skip-backward"),
204                 tr("P&revious"), this);
205     skipBackwardAct->setStatusTip(tr("Go back to the previous track"));
206     skipBackwardAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Left));
207 #if QT_VERSION >= 0x040600
208     skipBackwardAct->setPriority(QAction::LowPriority);
209 #endif
210     skipBackwardAct->setEnabled(false);
211     actions->insert("previous", skipBackwardAct);
212     connect(skipBackwardAct, SIGNAL(triggered()), mediaView, SLOT(skipBackward()));
213
214     skipAct = new QAction(QtIconLoader::icon("media-skip-forward"), tr("S&kip"), this);
215     skipAct->setStatusTip(tr("Skip to the next video"));
216     skipAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_Right) << QKeySequence(Qt::Key_MediaNext));
217     skipAct->setEnabled(false);
218     actions->insert("skip", skipAct);
219     connect(skipAct, SIGNAL(triggered()), mediaView, SLOT(skip()));
220
221     pauseAct = new QAction(QtIconLoader::icon("media-playback-pause"), tr("&Pause"), this);
222     pauseAct->setStatusTip(tr("Pause playback"));
223     pauseAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Space) << QKeySequence(Qt::Key_MediaPlay));
224     pauseAct->setEnabled(false);
225     actions->insert("pause", pauseAct);
226     connect(pauseAct, SIGNAL(triggered()), mediaView, SLOT(pause()));
227
228     fullscreenAct = new QAction(QtIconLoader::icon("view-fullscreen"), tr("&Full Screen"), this);
229     fullscreenAct->setStatusTip(tr("Go full screen"));
230     QList<QKeySequence> fsShortcuts;
231 #ifdef APP_MAC
232     fsShortcuts << QKeySequence(Qt::CTRL + Qt::META + Qt::Key_F);
233 #else
234     fsShortcuts << QKeySequence(Qt::Key_F11) << QKeySequence(Qt::ALT + Qt::Key_Return);
235 #endif
236     fullscreenAct->setShortcuts(fsShortcuts);
237     fullscreenAct->setShortcutContext(Qt::ApplicationShortcut);
238 #if QT_VERSION >= 0x040600
239     fullscreenAct->setPriority(QAction::LowPriority);
240 #endif
241     actions->insert("fullscreen", fullscreenAct);
242     connect(fullscreenAct, SIGNAL(triggered()), this, SLOT(fullscreen()));
243
244     compactViewAct = new QAction(tr("&Compact Mode"), this);
245     compactViewAct->setStatusTip(tr("Hide the playlist and the toolbar"));
246 #ifdef APP_MAC
247     compactViewAct->setShortcut(QKeySequence(Qt::CTRL + Qt::META + Qt::Key_C));
248 #else
249     compactViewAct->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_C));
250 #endif
251     compactViewAct->setCheckable(true);
252     compactViewAct->setChecked(false);
253     compactViewAct->setEnabled(false);
254     actions->insert("compactView", compactViewAct);
255     connect(compactViewAct, SIGNAL(toggled(bool)), this, SLOT(compactView(bool)));
256
257     webPageAct = new QAction(tr("Open the &YouTube Page"), this);
258     webPageAct->setStatusTip(tr("Go to the YouTube video page and pause playback"));
259     webPageAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Y));
260     webPageAct->setEnabled(false);
261     actions->insert("webpage", webPageAct);
262     connect(webPageAct, SIGNAL(triggered()), mediaView, SLOT(openWebPage()));
263
264     copyPageAct = new QAction(tr("Copy the YouTube &Link"), this);
265     copyPageAct->setStatusTip(tr("Copy the current video YouTube link to the clipboard"));
266     copyPageAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_L));
267     copyPageAct->setEnabled(false);
268     actions->insert("pagelink", copyPageAct);
269     connect(copyPageAct, SIGNAL(triggered()), mediaView, SLOT(copyWebPage()));
270
271     copyLinkAct = new QAction(tr("Copy the Video Stream &URL"), this);
272     copyLinkAct->setStatusTip(tr("Copy the current video stream URL to the clipboard"));
273     copyLinkAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_U));
274     copyLinkAct->setEnabled(false);
275     actions->insert("videolink", copyLinkAct);
276     connect(copyLinkAct, SIGNAL(triggered()), mediaView, SLOT(copyVideoLink()));
277
278     findVideoPartsAct = new QAction(tr("Find Video &Parts"), this);
279     findVideoPartsAct->setStatusTip(tr("Find other video parts hopefully in the right order"));
280     findVideoPartsAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_P));
281     findVideoPartsAct->setEnabled(false);
282     connect(findVideoPartsAct, SIGNAL(triggered()), mediaView, SLOT(findVideoParts()));
283     actions->insert("findVideoParts", findVideoPartsAct);
284
285     removeAct = new QAction(tr("&Remove"), this);
286     removeAct->setStatusTip(tr("Remove the selected videos from the playlist"));
287     removeAct->setShortcuts(QList<QKeySequence>() << QKeySequence("Del") << QKeySequence("Backspace"));
288     removeAct->setEnabled(false);
289     actions->insert("remove", removeAct);
290     connect(removeAct, SIGNAL(triggered()), mediaView, SLOT(removeSelected()));
291
292     moveUpAct = new QAction(tr("Move &Up"), this);
293     moveUpAct->setStatusTip(tr("Move up the selected videos in the playlist"));
294     moveUpAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Up));
295     moveUpAct->setEnabled(false);
296     actions->insert("moveUp", moveUpAct);
297     connect(moveUpAct, SIGNAL(triggered()), mediaView, SLOT(moveUpSelected()));
298
299     moveDownAct = new QAction(tr("Move &Down"), this);
300     moveDownAct->setStatusTip(tr("Move down the selected videos in the playlist"));
301     moveDownAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Down));
302     moveDownAct->setEnabled(false);
303     actions->insert("moveDown", moveDownAct);
304     connect(moveDownAct, SIGNAL(triggered()), mediaView, SLOT(moveDownSelected()));
305
306     clearAct = new QAction(tr("&Clear Recent Searches"), this);
307     clearAct->setMenuRole(QAction::ApplicationSpecificRole);
308     clearAct->setShortcuts(QList<QKeySequence>()
309                            << QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Delete)
310                            << QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Backspace));
311     clearAct->setStatusTip(tr("Clear the search history. Cannot be undone."));
312     clearAct->setEnabled(true);
313     actions->insert("clearRecentKeywords", clearAct);
314     connect(clearAct, SIGNAL(triggered()), SLOT(clearRecentKeywords()));
315
316     quitAct = new QAction(tr("&Quit"), this);
317     quitAct->setMenuRole(QAction::QuitRole);
318     quitAct->setShortcut(QKeySequence(QKeySequence::Quit));
319     quitAct->setStatusTip(tr("Bye"));
320     actions->insert("quit", quitAct);
321     connect(quitAct, SIGNAL(triggered()), SLOT(quit()));
322
323     siteAct = new QAction(tr("&Website"), this);
324     siteAct->setShortcut(QKeySequence::HelpContents);
325     siteAct->setStatusTip(tr("%1 on the Web").arg(Constants::NAME));
326     actions->insert("site", siteAct);
327     connect(siteAct, SIGNAL(triggered()), this, SLOT(visitSite()));
328
329 #if !defined(APP_MAC) && !defined(APP_WIN)
330     donateAct = new QAction(tr("Make a &Donation"), this);
331     donateAct->setStatusTip(tr("Please support the continued development of %1").arg(Constants::NAME));
332     actions->insert("donate", donateAct);
333     connect(donateAct, SIGNAL(triggered()), this, SLOT(donate()));
334 #endif
335
336     aboutAct = new QAction(tr("&About"), this);
337     aboutAct->setMenuRole(QAction::AboutRole);
338     aboutAct->setStatusTip(tr("Info about %1").arg(Constants::NAME));
339     actions->insert("about", aboutAct);
340     connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
341
342     // Invisible actions
343
344     searchFocusAct = new QAction(this);
345     searchFocusAct->setShortcut(QKeySequence::Find);
346     searchFocusAct->setStatusTip(tr("Search"));
347     actions->insert("search", searchFocusAct);
348     connect(searchFocusAct, SIGNAL(triggered()), this, SLOT(searchFocus()));
349     addAction(searchFocusAct);
350
351     volumeUpAct = new QAction(this);
352     volumeUpAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_Plus));
353     actions->insert("volume-up", volumeUpAct);
354     connect(volumeUpAct, SIGNAL(triggered()), this, SLOT(volumeUp()));
355     addAction(volumeUpAct);
356
357     volumeDownAct = new QAction(this);
358     volumeDownAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_Minus));
359     actions->insert("volume-down", volumeDownAct);
360     connect(volumeDownAct, SIGNAL(triggered()), this, SLOT(volumeDown()));
361     addAction(volumeDownAct);
362
363     volumeMuteAct = new QAction(this);
364     volumeMuteAct->setIcon(QtIconLoader::icon("audio-volume-high"));
365     volumeMuteAct->setStatusTip(tr("Mute volume"));
366     volumeMuteAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_E));
367     actions->insert("volume-mute", volumeMuteAct);
368     connect(volumeMuteAct, SIGNAL(triggered()), SLOT(volumeMute()));
369     addAction(volumeMuteAct);
370
371     QAction *definitionAct = new QAction(this);
372     definitionAct->setIcon(QtIconLoader::icon("video-display"));
373     definitionAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_D));
374     /*
375     QMenu *definitionMenu = new QMenu(this);
376     foreach (QString definition, VideoDefinition::getDefinitionNames()) {
377         definitionMenu->addAction(definition);
378     }
379     definitionAct->setMenu(definitionMenu);
380     */
381     actions->insert("definition", definitionAct);
382     connect(definitionAct, SIGNAL(triggered()), SLOT(toggleDefinitionMode()));
383     addAction(definitionAct);
384
385     QAction *action;
386
387     action = new QAction(QtIconLoader::icon("media-playback-start"), tr("&Manually Start Playing"), this);
388     action->setStatusTip(tr("Manually start playing videos"));
389     action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_B));
390     action->setCheckable(true);
391     connect(action, SIGNAL(toggled(bool)), SLOT(setManualPlay(bool)));
392     actions->insert("manualplay", action);
393
394     action = new QAction(tr("&Downloads"), this);
395     action->setStatusTip(tr("Show details about video downloads"));
396     action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_J));
397     action->setCheckable(true);
398     action->setIcon(QtIconLoader::icon("go-down"));
399     action->setVisible(false);
400     connect(action, SIGNAL(toggled(bool)), SLOT(toggleDownloads(bool)));
401     actions->insert("downloads", action);
402
403     action = new QAction(tr("&Download"), this);
404     action->setStatusTip(tr("Download the current video"));
405 #ifndef APP_NO_DOWNLOADS
406     action->setShortcut(QKeySequence::Save);
407 #endif
408     action->setIcon(QtIconLoader::icon("go-down"));
409     action->setEnabled(false);
410 #if QT_VERSION >= 0x040600
411     action->setPriority(QAction::LowPriority);
412 #endif
413     connect(action, SIGNAL(triggered()), mediaView, SLOT(downloadVideo()));
414     actions->insert("download", action);
415
416     /*
417     action = new QAction(tr("&Snapshot"), this);
418     action->setShortcut(QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_S));
419     actions->insert("snapshot", action);
420     connect(action, SIGNAL(triggered()), mediaView, SLOT(snapshot()));
421     */
422
423     QString shareTip = tr("Share the current video using %1");
424
425     action = new QAction("&Twitter", this);
426     action->setStatusTip(shareTip.arg("Twitter"));
427     actions->insert("twitter", action);
428     connect(action, SIGNAL(triggered()), mediaView, SLOT(shareViaTwitter()));
429
430     action = new QAction("&Facebook", this);
431     action->setStatusTip(shareTip.arg("Facebook"));
432     actions->insert("facebook", action);
433     connect(action, SIGNAL(triggered()), mediaView, SLOT(shareViaFacebook()));
434
435     action = new QAction("&Buffer", this);
436     action->setStatusTip(shareTip.arg("Buffer"));
437     actions->insert("buffer", action);
438     connect(action, SIGNAL(triggered()), mediaView, SLOT(shareViaBuffer()));
439
440     action = new QAction(tr("&Email"), this);
441     action->setStatusTip(shareTip.arg(tr("Email")));
442     actions->insert("email", action);
443     connect(action, SIGNAL(triggered()), mediaView, SLOT(shareViaEmail()));
444
445     action = new QAction(tr("&Close"), this);
446     action->setShortcut(QKeySequence(QKeySequence::Close));
447     actions->insert("close", action);
448     connect(action, SIGNAL(triggered()), SLOT(close()));
449
450     action = new QAction(Constants::NAME, this);
451     action->setShortcut(QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_1));
452     actions->insert("restore", action);
453     connect(action, SIGNAL(triggered()), SLOT(restore()));
454
455     action = new QAction(QtIconLoader::icon("go-top"), tr("&Float on Top"), this);
456     action->setCheckable(true);
457     actions->insert("ontop", action);
458     connect(action, SIGNAL(toggled(bool)), SLOT(floatOnTop(bool)));
459
460     action = new QAction(QtIconLoader::icon("media-playback-stop"), tr("&Stop After This Video"), this);
461     action->setShortcut(QKeySequence(Qt::SHIFT + Qt::Key_Escape));
462     action->setCheckable(true);
463     action->setEnabled(false);
464     actions->insert("stopafterthis", action);
465     connect(action, SIGNAL(toggled(bool)), SLOT(showStopAfterThisInStatusBar(bool)));
466
467     action = new QAction(tr("&Report an Issue..."), this);
468     actions->insert("report-issue", action);
469     connect(action, SIGNAL(triggered()), SLOT(reportIssue()));
470
471     action = new QAction(tr("&Refine Search..."), this);
472     action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_R));
473     action->setCheckable(true);
474     actions->insert("refine-search", action);
475
476     // common action properties
477     foreach (QAction *action, actions->values()) {
478
479         // add actions to the MainWindow so that they work
480         // when the menu is hidden
481         addAction(action);
482
483         // never autorepeat.
484         // unexperienced users tend to keep keys pressed for a "long" time
485         action->setAutoRepeat(false);
486
487         // set to something more meaningful then the toolbar text
488         if (!action->statusTip().isEmpty())
489             action->setToolTip(action->statusTip());
490
491         // show keyboard shortcuts in the status bar
492         if (!action->shortcut().isEmpty())
493             action->setStatusTip(action->statusTip() + " (" + action->shortcut().toString(QKeySequence::NativeText) + ")");
494
495         // no icons in menus
496         action->setIconVisibleInMenu(false);
497
498     }
499
500 }
501
502 void MainWindow::createMenus() {
503
504     QMap<QString, QMenu*> *menus = The::globalMenus();
505
506     fileMenu = menuBar()->addMenu(tr("&Application"));
507 #ifdef APP_DEMO
508     QAction* action = new QAction(tr("Buy %1...").arg(Constants::NAME), this);
509     action->setMenuRole(QAction::ApplicationSpecificRole);
510     connect(action, SIGNAL(triggered()), SLOT(buy()));
511     fileMenu->addAction(action);
512 #endif
513     fileMenu->addAction(clearAct);
514 #ifndef APP_MAC
515     fileMenu->addSeparator();
516 #endif
517     fileMenu->addAction(quitAct);
518
519     QMenu* playbackMenu = menuBar()->addMenu(tr("&Playback"));
520     menus->insert("playback", playbackMenu);
521     playbackMenu->addAction(pauseAct);
522     playbackMenu->addAction(stopAct);
523     playbackMenu->addAction(The::globalActions()->value("stopafterthis"));
524     playbackMenu->addSeparator();
525     playbackMenu->addAction(skipAct);
526     playbackMenu->addAction(skipBackwardAct);
527     playbackMenu->addSeparator();
528     playbackMenu->addAction(The::globalActions()->value("manualplay"));
529 #ifdef APP_MAC
530     MacSupport::dockMenu(playbackMenu);
531 #endif
532
533     playlistMenu = menuBar()->addMenu(tr("&Playlist"));
534     menus->insert("playlist", playlistMenu);
535     playlistMenu->addAction(removeAct);
536     playlistMenu->addSeparator();
537     playlistMenu->addAction(moveUpAct);
538     playlistMenu->addAction(moveDownAct);
539     playlistMenu->addSeparator();
540     playlistMenu->addAction(The::globalActions()->value("refine-search"));
541
542     QMenu* videoMenu = menuBar()->addMenu(tr("&Video"));
543     menus->insert("video", videoMenu);
544     videoMenu->addAction(findVideoPartsAct);
545     videoMenu->addSeparator();
546     videoMenu->addAction(webPageAct);
547     videoMenu->addSeparator();
548 #ifndef APP_NO_DOWNLOADS
549     videoMenu->addAction(The::globalActions()->value("download"));
550     // videoMenu->addAction(copyLinkAct);
551 #endif
552     // videoMenu->addAction(The::globalActions()->value("snapshot"));
553
554     QMenu* viewMenu = menuBar()->addMenu(tr("&View"));
555     menus->insert("view", viewMenu);
556     viewMenu->addAction(fullscreenAct);
557     viewMenu->addAction(compactViewAct);
558     viewMenu->addSeparator();
559     viewMenu->addAction(The::globalActions()->value("ontop"));
560
561     QMenu* shareMenu = menuBar()->addMenu(tr("&Share"));
562     menus->insert("share", shareMenu);
563     shareMenu->addAction(copyPageAct);
564     shareMenu->addSeparator();
565     shareMenu->addAction(The::globalActions()->value("twitter"));
566     shareMenu->addAction(The::globalActions()->value("facebook"));
567     shareMenu->addAction(The::globalActions()->value("buffer"));
568     shareMenu->addSeparator();
569     shareMenu->addAction(The::globalActions()->value("email"));
570
571 #ifdef APP_MAC
572     MacSupport::windowMenu(this);
573 #endif
574
575     helpMenu = menuBar()->addMenu(tr("&Help"));
576     helpMenu->addAction(siteAct);
577 #if !defined(APP_MAC) && !defined(APP_WIN)
578     helpMenu->addAction(donateAct);
579 #endif
580     helpMenu->addAction(The::globalActions()->value("report-issue"));
581     helpMenu->addAction(aboutAct);
582 }
583
584 void MainWindow::createToolBars() {
585
586     setUnifiedTitleAndToolBarOnMac(true);
587
588     mainToolBar = new QToolBar(this);
589 #if QT_VERSION < 0x040600 | defined(APP_MAC)
590     mainToolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
591 #else
592     mainToolBar->setToolButtonStyle(Qt::ToolButtonFollowStyle);
593 #endif
594     mainToolBar->setFloatable(false);
595     mainToolBar->setMovable(false);
596
597 #if defined(APP_MAC) | defined(APP_WIN)
598     mainToolBar->setIconSize(QSize(32, 32));
599 #endif
600
601     mainToolBar->addAction(stopAct);
602     mainToolBar->addAction(pauseAct);
603     mainToolBar->addAction(skipAct);
604
605     bool addFullScreenAct = true;
606 #ifdef Q_WS_MAC
607     addFullScreenAct = !mac::CanGoFullScreen(winId());
608 #endif
609     if (addFullScreenAct) mainToolBar->addAction(fullscreenAct);
610
611 #ifndef APP_NO_DOWNLOADS
612     mainToolBar->addAction(The::globalActions()->value("download"));
613 #endif
614
615     mainToolBar->addWidget(new Spacer());
616
617     QFont smallerFont = FontUtils::small();
618     currentTime = new QLabel(mainToolBar);
619     currentTime->setFont(smallerFont);
620     mainToolBar->addWidget(currentTime);
621
622     mainToolBar->addWidget(new Spacer());
623
624     seekSlider = new Phonon::SeekSlider(this);
625     seekSlider->setIconVisible(false);
626     seekSlider->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
627     mainToolBar->addWidget(seekSlider);
628
629 /*
630     mainToolBar->addWidget(new Spacer());
631     slider = new QSlider(this);
632     slider->setOrientation(Qt::Horizontal);
633     slider->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
634     mainToolBar->addWidget(slider);
635 */
636
637     mainToolBar->addWidget(new Spacer());
638
639     totalTime = new QLabel(mainToolBar);
640     totalTime->setFont(smallerFont);
641     mainToolBar->addWidget(totalTime);
642
643     mainToolBar->addWidget(new Spacer());
644
645     mainToolBar->addAction(volumeMuteAct);
646
647     volumeSlider = new Phonon::VolumeSlider(this);
648     volumeSlider->setMuteVisible(false);
649     // qDebug() << volumeSlider->children();
650     // status tip for the volume slider
651     QSlider* volumeQSlider = volumeSlider->findChild<QSlider*>();
652     if (volumeQSlider)
653         volumeQSlider->setStatusTip(tr("Press %1 to raise the volume, %2 to lower it").arg(
654                 volumeUpAct->shortcut().toString(QKeySequence::NativeText), volumeDownAct->shortcut().toString(QKeySequence::NativeText)));
655     // this makes the volume slider smaller
656     volumeSlider->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
657     mainToolBar->addWidget(volumeSlider);
658
659     mainToolBar->addWidget(new Spacer());
660
661 #ifdef APP_MAC
662     SearchWrapper* searchWrapper = new SearchWrapper(this);
663     toolbarSearch = searchWrapper->getSearchLineEdit();
664 #else
665     toolbarSearch = new SearchLineEdit(this);
666 #endif
667     toolbarSearch->setMinimumWidth(toolbarSearch->fontInfo().pixelSize()*15);
668     toolbarSearch->setSuggester(new YouTubeSuggest(this));
669     connect(toolbarSearch, SIGNAL(search(const QString&)), this, SLOT(startToolbarSearch(const QString&)));
670     connect(toolbarSearch, SIGNAL(suggestionAccepted(const QString&)), SLOT(startToolbarSearch(const QString&)));
671     toolbarSearch->setStatusTip(searchFocusAct->statusTip());
672 #ifdef APP_MAC
673     mainToolBar->addWidget(searchWrapper);
674 #else
675     mainToolBar->addWidget(toolbarSearch);
676     Spacer* spacer = new Spacer();
677     // spacer->setWidth(4);
678     mainToolBar->addWidget(spacer);
679 #endif
680
681     addToolBar(mainToolBar);
682 }
683
684 void MainWindow::createStatusBar() {
685     QToolBar* toolBar = new QToolBar(this);
686     statusToolBar = toolBar;
687     toolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
688     toolBar->setIconSize(QSize(16, 16));
689     toolBar->addAction(The::globalActions()->value("downloads"));
690     toolBar->addAction(The::globalActions()->value("definition"));
691     statusBar()->addPermanentWidget(toolBar);
692     statusBar()->show();
693 }
694
695 void MainWindow::showStopAfterThisInStatusBar(bool show) {
696     QAction* action = The::globalActions()->value("stopafterthis");
697     showActionInStatusBar(action, show);
698 }
699
700 void MainWindow::showActionInStatusBar(QAction* action, bool show) {
701     if (show) {
702         statusToolBar->insertAction(statusToolBar->actions().first(), action);
703     } else {
704         statusToolBar->removeAction(action);
705     }
706 }
707
708 void MainWindow::readSettings() {
709     QSettings settings;
710     if (settings.contains("geometry")) {
711         restoreGeometry(settings.value("geometry").toByteArray());
712 #ifdef APP_MAC
713     MacSupport::fixGeometry(this);
714 #endif
715     } else {
716         setGeometry(100, 100, 1000, 500);
717     }
718     setDefinitionMode(settings.value("definition", VideoDefinition::getDefinitionNames().first()).toString());
719     audioOutput->setVolume(settings.value("volume", 1).toDouble());
720     audioOutput->setMuted(settings.value("volumeMute").toBool());
721     The::globalActions()->value("manualplay")->setChecked(settings.value("manualplay", false).toBool());
722 }
723
724 void MainWindow::writeSettings() {
725     QSettings settings;
726
727     settings.setValue("geometry", saveGeometry());
728     mediaView->saveSplitterState();
729
730     settings.setValue("volume", audioOutput->volume());
731     settings.setValue("volumeMute", audioOutput->isMuted());
732     settings.setValue("manualplay", The::globalActions()->value("manualplay")->isChecked());
733 }
734
735 void MainWindow::goBack() {
736     if ( history->size() > 1 ) {
737         history->pop();
738         QWidget *widget = history->pop();
739         showWidget(widget);
740     }
741 }
742
743 void MainWindow::showWidget ( QWidget* widget ) {
744
745     if (compactViewAct->isChecked())
746         compactViewAct->toggle();
747
748     setUpdatesEnabled(false);
749
750     // call hide method on the current view
751     View* oldView = dynamic_cast<View *> (views->currentWidget());
752     if (oldView) {
753         oldView->disappear();
754         views->currentWidget()->setEnabled(false);
755     }
756
757     // call show method on the new view
758     View* newView = dynamic_cast<View *> (widget);
759     if (newView) {
760         widget->setEnabled(true);
761         newView->appear();
762         QMap<QString,QVariant> metadata = newView->metadata();
763         QString windowTitle = metadata.value("title").toString();
764         if (windowTitle.length())
765             windowTitle += " - ";
766         setWindowTitle(windowTitle + Constants::NAME);
767         statusBar()->showMessage((metadata.value("description").toString()));
768     }
769
770     stopAct->setEnabled(widget == mediaView);
771     compactViewAct->setEnabled(widget == mediaView);
772     webPageAct->setEnabled(widget == mediaView);
773     copyPageAct->setEnabled(widget == mediaView);
774     copyLinkAct->setEnabled(widget == mediaView);
775     findVideoPartsAct->setEnabled(widget == mediaView);
776     toolbarSearch->setEnabled(widget == searchView || widget == mediaView || widget == downloadView);
777
778     if (widget == searchView) {
779         skipAct->setEnabled(false);
780         The::globalActions()->value("previous")->setEnabled(false);
781         The::globalActions()->value("download")->setEnabled(false);
782         The::globalActions()->value("stopafterthis")->setEnabled(false);
783     }
784
785     The::globalActions()->value("twitter")->setEnabled(widget == mediaView);
786     The::globalActions()->value("facebook")->setEnabled(widget == mediaView);
787     The::globalActions()->value("buffer")->setEnabled(widget == mediaView);
788     The::globalActions()->value("email")->setEnabled(widget == mediaView);
789
790     aboutAct->setEnabled(widget != aboutView);
791     The::globalActions()->value("downloads")->setChecked(widget == downloadView);
792
793     // toolbar only for the mediaView
794     /* mainToolBar->setVisible(
795             (widget == mediaView && !compactViewAct->isChecked())
796             || widget == downloadView
797             ); */
798
799     setUpdatesEnabled(true);
800
801     QWidget *oldWidget = views->currentWidget();
802     if (oldWidget)
803         oldWidget->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
804
805     views->setCurrentWidget(widget);
806     widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
807     // adjustSize();
808
809 #ifndef Q_WS_X11
810     Extra::fadeInWidget(oldWidget, widget);
811 #endif
812
813     history->push(widget);
814 }
815
816 void MainWindow::about() {
817     if (!aboutView) {
818         aboutView = new AboutView(this);
819         views->addWidget(aboutView);
820     }
821     showWidget(aboutView);
822 }
823
824 void MainWindow::visitSite() {
825     QUrl url(Constants::WEBSITE);
826     statusBar()->showMessage(QString(tr("Opening %1").arg(url.toString())));
827     QDesktopServices::openUrl(url);
828 }
829
830 void MainWindow::donate() {
831     QUrl url(QString(Constants::WEBSITE) + "#donate");
832     statusBar()->showMessage(QString(tr("Opening %1").arg(url.toString())));
833     QDesktopServices::openUrl(url);
834 }
835
836 void MainWindow::reportIssue() {
837     QUrl url("http://flavio.tordini.org/forums/forum/minitube-forums/minitube-troubleshooting");
838     QDesktopServices::openUrl(url);
839 }
840
841 void MainWindow::quit() {
842 #ifdef APP_MAC
843     if (!confirmQuit()) {
844         return;
845     }
846 #endif
847     // do not save geometry when in full screen or in compact mode
848     if (!m_fullscreen && !compactViewAct->isChecked()) {
849         writeSettings();
850     }
851     Temporary::deleteAll();
852     qApp->quit();
853 }
854
855 void MainWindow::closeEvent(QCloseEvent *event) {
856 #ifdef APP_MAC
857     mac::closeWindow(winId());
858     event->ignore();
859 #else
860     if (!confirmQuit()) {
861         event->ignore();
862         return;
863     }
864     QWidget::closeEvent(event);
865     quit();
866 #endif
867 }
868
869 bool MainWindow::confirmQuit() {
870     if (DownloadManager::instance()->activeItems() > 0) {
871         QMessageBox msgBox(this);
872         msgBox.setIconPixmap(QPixmap(":/images/app.png").scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation));
873         msgBox.setText(tr("Do you want to exit %1 with a download in progress?").arg(Constants::NAME));
874         msgBox.setInformativeText(tr("If you close %1 now, this download will be cancelled.").arg(Constants::NAME));
875         msgBox.setModal(true);
876         // make it a "sheet" on the Mac
877         msgBox.setWindowModality(Qt::WindowModal);
878
879         msgBox.addButton(tr("Close and cancel download"), QMessageBox::RejectRole);
880         QPushButton *waitButton = msgBox.addButton(tr("Wait for download to finish"), QMessageBox::ActionRole);
881
882         msgBox.exec();
883
884         if (msgBox.clickedButton() == waitButton) {
885             return false;
886         }
887     }
888     return true;
889 }
890
891 void MainWindow::showSearch() {
892     showWidget(searchView);
893     currentTime->clear();
894     totalTime->clear();
895 }
896
897 void MainWindow::showMedia(SearchParams *searchParams) {
898     mediaView->search(searchParams);
899     showWidget(mediaView);
900 }
901
902 void MainWindow::stateChanged(Phonon::State newState, Phonon::State /* oldState */) {
903
904     // qDebug() << "Phonon state: " << newState;
905
906     switch (newState) {
907
908     case Phonon::ErrorState:
909         if (mediaObject->errorType() == Phonon::FatalError) {
910             // Do not display because we try to play incomplete video files and sometimes trigger this
911             // We retry automatically (in MediaView) so no need to show it
912             // statusBar()->showMessage(tr("Fatal error: %1").arg(mediaObject->errorString()));
913         } else {
914             statusBar()->showMessage(tr("Error: %1").arg(mediaObject->errorString()));
915         }
916         break;
917
918          case Phonon::PlayingState:
919         pauseAct->setEnabled(true);
920         pauseAct->setIcon(QtIconLoader::icon("media-playback-pause"));
921         pauseAct->setText(tr("&Pause"));
922         pauseAct->setStatusTip(tr("Pause playback") + " (" +  pauseAct->shortcut().toString(QKeySequence::NativeText) + ")");
923         // stopAct->setEnabled(true);
924         break;
925
926          case Phonon::StoppedState:
927         pauseAct->setEnabled(false);
928         // stopAct->setEnabled(false);
929         break;
930
931          case Phonon::PausedState:
932         pauseAct->setEnabled(true);
933         pauseAct->setIcon(QtIconLoader::icon("media-playback-start"));
934         pauseAct->setText(tr("&Play"));
935         pauseAct->setStatusTip(tr("Resume playback") + " (" +  pauseAct->shortcut().toString(QKeySequence::NativeText) + ")");
936         // stopAct->setEnabled(true);
937         break;
938
939          case Phonon::BufferingState:
940          case Phonon::LoadingState:
941         pauseAct->setEnabled(false);
942         currentTime->clear();
943         totalTime->clear();
944         // stopAct->setEnabled(true);
945         break;
946
947          default:
948         ;
949     }
950 }
951
952 void MainWindow::stop() {
953     mediaView->stop();
954     showSearch();
955 }
956
957 void MainWindow::resizeEvent(QResizeEvent*) {
958 #ifdef Q_WS_MAC
959     if (mac::CanGoFullScreen(winId())) {
960         bool isFullscreen = mac::IsFullScreen(winId());
961         if (isFullscreen != m_fullscreen) {
962             if (compactViewAct->isChecked()) {
963                 compactViewAct->setChecked(false);
964                 compactView(false);
965             }
966             m_fullscreen = isFullscreen;
967             updateUIForFullscreen();
968         }
969     }
970 #endif
971 }
972
973 void MainWindow::fullscreen() {
974
975     if (compactViewAct->isChecked())
976         compactViewAct->toggle();
977
978 #ifdef Q_WS_MAC
979     WId handle = winId();
980     if (mac::CanGoFullScreen(handle)) {
981         mainToolBar->setVisible(true);
982         mac::ToggleFullScreen(handle);
983         return;
984     }
985 #endif
986
987     m_fullscreen = !m_fullscreen;
988
989     if (m_fullscreen) {
990         // Enter full screen
991
992         m_maximized = isMaximized();
993
994         // save geometry now, if the user quits when in full screen
995         // geometry won't be saved
996         writeSettings();
997
998 #ifdef Q_WS_MAC
999         MacSupport::enterFullScreen(this, views);
1000 #else
1001         mainToolBar->hide();
1002         showFullScreen();
1003 #endif
1004
1005     } else {
1006         // Exit full screen
1007
1008 #ifdef Q_WS_MAC
1009         MacSupport::exitFullScreen(this, views);
1010 #else
1011         mainToolBar->show();
1012         if (m_maximized) showMaximized();
1013         else showNormal();
1014 #endif
1015
1016         // Make sure the window has focus
1017         activateWindow();
1018
1019     }
1020
1021     updateUIForFullscreen();
1022
1023 }
1024
1025 void MainWindow::updateUIForFullscreen() {
1026     static QList<QKeySequence> fsShortcuts;
1027     static QString fsText;
1028
1029     if (m_fullscreen) {
1030         fsShortcuts = fullscreenAct->shortcuts();
1031         fsText = fullscreenAct->text();
1032         fullscreenAct->setShortcuts(QList<QKeySequence>(fsShortcuts)
1033                                     << QKeySequence(Qt::Key_Escape));
1034         fullscreenAct->setText(tr("Leave &Full Screen"));
1035     } else {
1036         fullscreenAct->setShortcuts(fsShortcuts);
1037         fullscreenAct->setText(fsText);
1038     }
1039
1040     // No compact view action when in full screen
1041     compactViewAct->setVisible(!m_fullscreen);
1042     compactViewAct->setChecked(false);
1043
1044     // Hide anything but the video
1045     mediaView->setPlaylistVisible(!m_fullscreen);
1046     statusBar()->setVisible(!m_fullscreen);
1047
1048 #ifndef APP_MAC
1049     menuBar()->setVisible(!m_fullscreen);
1050 #endif
1051
1052     if (m_fullscreen) {
1053         stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_MediaStop));
1054     } else {
1055         stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
1056     }
1057
1058 #ifdef Q_WS_MAC
1059     MacSupport::fullScreenActions(The::globalActions()->values(), m_fullscreen);
1060 #endif
1061
1062     if (views->currentWidget() == mediaView)
1063         mediaView->setFocus();
1064
1065     if (!m_fullscreen) {
1066         mouseTimer->stop();
1067         unsetCursor();
1068     }
1069 }
1070
1071 void MainWindow::compactView(bool enable) {
1072
1073     static QList<QKeySequence> compactShortcuts;
1074     static QList<QKeySequence> stopShortcuts;
1075
1076     const static QString key = "compactGeometry";
1077     QSettings settings;
1078
1079 #ifndef APP_MAC
1080     menuBar()->setVisible(!enable);
1081 #endif
1082
1083     if (enable) {
1084         setMinimumSize(160, 120);
1085 #ifdef Q_WS_MAC
1086         mac::RemoveFullScreenWindow(winId());
1087 #endif
1088         writeSettings();
1089
1090         if (settings.contains(key))
1091             restoreGeometry(settings.value(key).toByteArray());
1092         else
1093             resize(320, 240);
1094
1095         mainToolBar->setVisible(!enable);
1096         mediaView->setPlaylistVisible(!enable);
1097         statusBar()->setVisible(!enable);
1098
1099         compactShortcuts = compactViewAct->shortcuts();
1100         stopShortcuts = stopAct->shortcuts();
1101
1102         QList<QKeySequence> newStopShortcuts(stopShortcuts);
1103         newStopShortcuts.removeAll(QKeySequence(Qt::Key_Escape));
1104         stopAct->setShortcuts(newStopShortcuts);
1105         compactViewAct->setShortcuts(QList<QKeySequence>(compactShortcuts) << QKeySequence(Qt::Key_Escape));
1106
1107         // ensure focus does not end up to the search box
1108         // as it would steal the Space shortcut
1109         mediaView->setFocus();
1110
1111     } else {
1112         // unset minimum size
1113         setMinimumSize(0, 0);
1114 #ifdef Q_WS_MAC
1115         mac::SetupFullScreenWindow(winId());
1116 #endif
1117         settings.setValue(key, saveGeometry());
1118         mainToolBar->setVisible(!enable);
1119         mediaView->setPlaylistVisible(!enable);
1120         statusBar()->setVisible(!enable);
1121         readSettings();
1122
1123         compactViewAct->setShortcuts(compactShortcuts);
1124         stopAct->setShortcuts(stopShortcuts);
1125     }
1126
1127     // auto float on top
1128     floatOnTop(enable);
1129 }
1130
1131 void MainWindow::searchFocus() {
1132     toolbarSearch->selectAll();
1133     toolbarSearch->setFocus();
1134 }
1135
1136 void MainWindow::initPhonon() {
1137     // Phonon initialization
1138     if (mediaObject) delete mediaObject;
1139     if (audioOutput) delete audioOutput;
1140     mediaObject = new Phonon::MediaObject(this);
1141     mediaObject->setTickInterval(100);
1142     connect(mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
1143             this, SLOT(stateChanged(Phonon::State, Phonon::State)));
1144     connect(mediaObject, SIGNAL(tick(qint64)), this, SLOT(tick(qint64)));
1145     connect(mediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64)));
1146     seekSlider->setMediaObject(mediaObject);
1147     audioOutput = new Phonon::AudioOutput(Phonon::VideoCategory, this);
1148     connect(audioOutput, SIGNAL(volumeChanged(qreal)), this, SLOT(volumeChanged(qreal)));
1149     connect(audioOutput, SIGNAL(mutedChanged(bool)), this, SLOT(volumeMutedChanged(bool)));
1150     volumeSlider->setAudioOutput(audioOutput);
1151     Phonon::createPath(mediaObject, audioOutput);
1152 }
1153
1154 void MainWindow::tick(qint64 time) {
1155     if (time <= 0) {
1156         // the "if" is important because tick is continually called
1157         // and we don't want to paint the toolbar every 100ms
1158         if (!currentTime->text().isEmpty()) currentTime->clear();
1159         return;
1160     }
1161
1162     currentTime->setText(formatTime(time));
1163
1164     // remaining time
1165     const qint64 remainingTime = mediaObject->remainingTime();
1166     currentTime->setStatusTip(tr("Remaining time: %1").arg(formatTime(remainingTime)));
1167
1168     /*
1169     slider->blockSignals(true);
1170     slider->setValue(time/1000);
1171     slider->blockSignals(false);
1172     */
1173 }
1174
1175 void MainWindow::totalTimeChanged(qint64 time) {
1176     if (time <= 0) {
1177         totalTime->clear();
1178         return;
1179     }
1180     totalTime->setText(formatTime(time));
1181
1182     /*
1183     slider->blockSignals(true);
1184     slider->setMaximum(time/1000);
1185     slider->blockSignals(false);
1186     */
1187
1188 }
1189
1190 QString MainWindow::formatTime(qint64 time) {
1191     QTime displayTime;
1192     displayTime = displayTime.addMSecs(time);
1193     QString timeString;
1194     // 60 * 60 * 1000 = 3600000
1195     if (time > 3600000)
1196         timeString = displayTime.toString("h:mm:ss");
1197     else
1198         timeString = displayTime.toString("m:ss");
1199     return timeString;
1200 }
1201
1202 void MainWindow::volumeUp() {
1203     qreal newVolume = volumeSlider->audioOutput()->volume() + .1;
1204     if (newVolume > volumeSlider->maximumVolume())
1205         newVolume = volumeSlider->maximumVolume();
1206     volumeSlider->audioOutput()->setVolume(newVolume);
1207 }
1208
1209 void MainWindow::volumeDown() {
1210     qreal newVolume = volumeSlider->audioOutput()->volume() - .1;
1211     if (newVolume < 0)
1212         newVolume = 0;
1213     volumeSlider->audioOutput()->setVolume(newVolume);
1214 }
1215
1216 void MainWindow::volumeMute() {
1217     volumeSlider->audioOutput()->setMuted(!volumeSlider->audioOutput()->isMuted());
1218 }
1219
1220 void MainWindow::volumeChanged(qreal newVolume) {
1221     // automatically unmute when volume changes
1222     if (volumeSlider->audioOutput()->isMuted())
1223         volumeSlider->audioOutput()->setMuted(false);
1224     statusBar()->showMessage(tr("Volume at %1%").arg((int)(newVolume*100)));
1225 }
1226
1227 void MainWindow::volumeMutedChanged(bool muted) {
1228     if (muted) {
1229         volumeMuteAct->setIcon(QtIconLoader::icon("audio-volume-muted"));
1230         statusBar()->showMessage(tr("Volume is muted"));
1231     } else {
1232         volumeMuteAct->setIcon(QtIconLoader::icon("audio-volume-high"));
1233         statusBar()->showMessage(tr("Volume is unmuted"));
1234     }
1235 }
1236
1237 void MainWindow::setDefinitionMode(QString definitionName) {
1238     QAction *definitionAct = The::globalActions()->value("definition");
1239     definitionAct->setText(definitionName);
1240     definitionAct->setStatusTip(tr("Maximum video definition set to %1").arg(definitionAct->text())
1241                                 + " (" +  definitionAct->shortcut().toString(QKeySequence::NativeText) + ")");
1242     statusBar()->showMessage(definitionAct->statusTip());
1243     QSettings settings;
1244     settings.setValue("definition", definitionName);
1245 }
1246
1247 void MainWindow::toggleDefinitionMode() {
1248     QSettings settings;
1249     QString currentDefinition = settings.value("definition").toString();
1250     QStringList definitionNames = VideoDefinition::getDefinitionNames();
1251     int currentIndex = definitionNames.indexOf(currentDefinition);
1252     int nextIndex = 0;
1253     if (currentIndex != definitionNames.size() - 1) {
1254         nextIndex = currentIndex + 1;
1255     }
1256     QString nextDefinition = definitionNames.at(nextIndex);
1257     setDefinitionMode(nextDefinition);
1258 }
1259
1260 void MainWindow::showFullscreenToolbar(bool show) {
1261     if (!m_fullscreen) return;
1262     mainToolBar->setVisible(show);
1263 }
1264
1265 void MainWindow::showFullscreenPlaylist(bool show) {
1266     if (!m_fullscreen) return;
1267     mediaView->setPlaylistVisible(show);
1268 }
1269
1270 void MainWindow::clearRecentKeywords() {
1271     QSettings settings;
1272     settings.remove("recentKeywords");
1273     settings.remove("recentChannels");
1274     searchView->updateRecentKeywords();
1275     searchView->updateRecentChannels();
1276     statusBar()->showMessage(tr("Your privacy is now safe"));
1277 }
1278
1279 void MainWindow::setManualPlay(bool enabled) {
1280     QSettings settings;
1281     settings.setValue("manualplay", QVariant::fromValue(enabled));
1282     showActionInStatusBar(The::globalActions()->value("manualplay"), enabled);
1283 }
1284
1285 void MainWindow::updateDownloadMessage(QString message) {
1286     The::globalActions()->value("downloads")->setText(message);
1287 }
1288
1289 void MainWindow::downloadsFinished() {
1290     The::globalActions()->value("downloads")->setText(tr("&Downloads"));
1291     statusBar()->showMessage(tr("Downloads complete"));
1292 }
1293
1294 void MainWindow::toggleDownloads(bool show) {
1295
1296     if (show) {
1297         stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_MediaStop));
1298         The::globalActions()->value("downloads")->setShortcuts(
1299                 QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_J)
1300                 << QKeySequence(Qt::Key_Escape));
1301     } else {
1302         The::globalActions()->value("downloads")->setShortcuts(
1303                 QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_J));
1304         stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
1305     }
1306
1307     if (!downloadView) {
1308         downloadView = new DownloadView(this);
1309         views->addWidget(downloadView);
1310     }
1311     if (show) showWidget(downloadView);
1312     else goBack();
1313 }
1314
1315 void MainWindow::startToolbarSearch(QString query) {
1316     query = query.trimmed();
1317
1318     // check for empty query
1319     if (query.length() == 0) {
1320         return;
1321     }
1322
1323     SearchParams *searchParams = new SearchParams();
1324     searchParams->setKeywords(query);
1325
1326     // go!
1327     showMedia(searchParams);
1328 }
1329
1330 void MainWindow::dragEnterEvent(QDragEnterEvent *event) {
1331     if (event->mimeData()->hasFormat("text/uri-list")) {
1332         QList<QUrl> urls = event->mimeData()->urls();
1333         if (urls.isEmpty())
1334             return;
1335         QUrl url = urls.first();
1336         QString videoId = YouTubeSearch::videoIdFromUrl(url.toString());
1337         if (!videoId.isNull())
1338             event->acceptProposedAction();
1339     }
1340 }
1341
1342 void MainWindow::dropEvent(QDropEvent *event) {
1343     QList<QUrl> urls = event->mimeData()->urls();
1344     if (urls.isEmpty())
1345         return;
1346     QUrl url = urls.first();
1347     QString videoId = YouTubeSearch::videoIdFromUrl(url.toString());
1348     if (!videoId.isNull()) {
1349         setWindowTitle(url.toString());
1350         SearchParams *searchParams = new SearchParams();
1351         searchParams->setKeywords(videoId);
1352         showMedia(searchParams);
1353     }
1354 }
1355
1356 void MainWindow::checkForUpdate() {
1357     static const QString updateCheckKey = "updateCheck";
1358
1359     // check every 24h
1360     QSettings settings;
1361     uint unixTime = QDateTime::currentDateTime().toTime_t();
1362     int lastCheck = settings.value(updateCheckKey).toInt();
1363     int secondsSinceLastCheck = unixTime - lastCheck;
1364     // qDebug() << "secondsSinceLastCheck" << unixTime << lastCheck << secondsSinceLastCheck;
1365     if (secondsSinceLastCheck < 86400) return;
1366
1367     // check it out
1368     if (updateChecker) delete updateChecker;
1369     updateChecker = new UpdateChecker();
1370     connect(updateChecker, SIGNAL(newVersion(QString)),
1371             this, SLOT(gotNewVersion(QString)));
1372     updateChecker->checkForUpdate();
1373     settings.setValue(updateCheckKey, unixTime);
1374
1375 }
1376
1377 void MainWindow::gotNewVersion(QString version) {
1378     if (updateChecker) {
1379         delete updateChecker;
1380         updateChecker = 0;
1381     }
1382
1383 #if defined(APP_DEMO) || defined(APP_MAC_STORE) || defined(APP_USC)
1384     return;
1385 #endif
1386
1387     QSettings settings;
1388     QString checkedVersion = settings.value("checkedVersion").toString();
1389     if (checkedVersion == version) return;
1390
1391     QMessageBox msgBox(this);
1392     msgBox.setIconPixmap(QPixmap(":/images/app.png").scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation));
1393     msgBox.setText(tr("%1 version %2 is now available.").arg(Constants::NAME, version));
1394
1395     msgBox.setModal(true);
1396     // make it a "sheet" on the Mac
1397     msgBox.setWindowModality(Qt::WindowModal);
1398
1399     QPushButton* laterButton = 0;
1400     QPushButton* updateButton = 0;
1401
1402 #if defined(APP_MAC) || defined(APP_WIN)
1403     msgBox.setInformativeText(
1404                 tr("To get the updated version, download %1 again from the link you received via email and reinstall.")
1405                 .arg(Constants::NAME)
1406                 );
1407     laterButton = msgBox.addButton(tr("Remind me later"), QMessageBox::RejectRole);
1408     msgBox.addButton(QMessageBox::Ok);
1409 #else
1410     msgBox.addButton(QMessageBox::Close);
1411     updateButton = msgBox.addButton(tr("Update"), QMessageBox::AcceptRole);
1412 #endif
1413
1414     msgBox.exec();
1415
1416     if (msgBox.clickedButton() != laterButton) {
1417         settings.setValue("checkedVersion", version);
1418     }
1419
1420     if (updateButton && msgBox.clickedButton() == updateButton) {
1421         QDesktopServices::openUrl(QUrl(QLatin1String(Constants::WEBSITE) + "#download"));
1422     }
1423
1424 }
1425
1426 void MainWindow::floatOnTop(bool onTop) {
1427     showActionInStatusBar(The::globalActions()->value("ontop"), onTop);
1428 #ifdef APP_MAC
1429     mac::floatOnTop(winId(), onTop);
1430     return;
1431 #endif
1432     if (onTop) {
1433         setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
1434         show();
1435     } else {
1436         setWindowFlags(windowFlags() ^ Qt::WindowStaysOnTopHint);
1437         show();
1438     }
1439 }
1440
1441 void MainWindow::restore() {
1442 #ifdef APP_MAC
1443     mac::uncloseWindow(window()->winId());
1444 #endif
1445 }
1446
1447 void MainWindow::messageReceived(const QString &message) {
1448     if (message == "--toggle-playing") {
1449         if (pauseAct->isEnabled()) pauseAct->trigger();
1450     } else if (message == "--next") {
1451         if (skipAct->isEnabled()) skipAct->trigger();
1452     } else if (message == "--previous") {
1453         if (skipBackwardAct->isEnabled()) skipBackwardAct->trigger();
1454     }  else if (message.startsWith("--")) {
1455         MainWindow::printHelp();
1456     } else if (!message.isEmpty()) {
1457         SearchParams *searchParams = new SearchParams();
1458         searchParams->setKeywords(message);
1459         showMedia(searchParams);
1460     }
1461 }
1462
1463 void MainWindow::hideMouse() {
1464     setCursor(Qt::BlankCursor);
1465     mediaView->setPlaylistVisible(false);
1466 #ifndef APP_MAC
1467     mainToolBar->setVisible(false);
1468 #endif
1469 }
1470
1471 void MainWindow::printHelp() {
1472     QString msg = QString("%1 %2\n\n").arg(Constants::NAME, Constants::VERSION);
1473     msg += "Usage: minitube [options]\n";
1474     msg += "Options:\n";
1475     msg += "  --toggle-playing\t";
1476     msg += "Start or pause playback.\n";
1477     msg += "  --next\t\t";
1478     msg += "Skip to the next video.\n";
1479     msg += "  --previous\t\t";
1480     msg += "Go back to the previous video.\n";
1481     std::cout << msg.toLocal8Bit().data();
1482 }