]> git.sur5r.net Git - minitube/blob - src/MainWindow.cpp
Imported Upstream version 1.9
[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         hideMouse();
1067     } else {
1068         mouseTimer->stop();
1069         unsetCursor();
1070     }
1071 }
1072
1073 void MainWindow::compactView(bool enable) {
1074
1075     static QList<QKeySequence> compactShortcuts;
1076     static QList<QKeySequence> stopShortcuts;
1077
1078     const static QString key = "compactGeometry";
1079     QSettings settings;
1080
1081 #ifndef APP_MAC
1082     menuBar()->setVisible(!enable);
1083 #endif
1084
1085     if (enable) {
1086         setMinimumSize(160, 120);
1087 #ifdef Q_WS_MAC
1088         mac::RemoveFullScreenWindow(winId());
1089 #endif
1090         writeSettings();
1091
1092         if (settings.contains(key))
1093             restoreGeometry(settings.value(key).toByteArray());
1094         else
1095             resize(320, 240);
1096
1097         mainToolBar->setVisible(!enable);
1098         mediaView->setPlaylistVisible(!enable);
1099         statusBar()->setVisible(!enable);
1100
1101         compactShortcuts = compactViewAct->shortcuts();
1102         stopShortcuts = stopAct->shortcuts();
1103
1104         QList<QKeySequence> newStopShortcuts(stopShortcuts);
1105         newStopShortcuts.removeAll(QKeySequence(Qt::Key_Escape));
1106         stopAct->setShortcuts(newStopShortcuts);
1107         compactViewAct->setShortcuts(QList<QKeySequence>(compactShortcuts) << QKeySequence(Qt::Key_Escape));
1108
1109         // ensure focus does not end up to the search box
1110         // as it would steal the Space shortcut
1111         mediaView->setFocus();
1112
1113     } else {
1114         // unset minimum size
1115         setMinimumSize(0, 0);
1116 #ifdef Q_WS_MAC
1117         mac::SetupFullScreenWindow(winId());
1118 #endif
1119         settings.setValue(key, saveGeometry());
1120         mainToolBar->setVisible(!enable);
1121         mediaView->setPlaylistVisible(!enable);
1122         statusBar()->setVisible(!enable);
1123         readSettings();
1124
1125         compactViewAct->setShortcuts(compactShortcuts);
1126         stopAct->setShortcuts(stopShortcuts);
1127     }
1128
1129     // auto float on top
1130     floatOnTop(enable);
1131 }
1132
1133 void MainWindow::searchFocus() {
1134     toolbarSearch->selectAll();
1135     toolbarSearch->setFocus();
1136 }
1137
1138 void MainWindow::initPhonon() {
1139     // Phonon initialization
1140     if (mediaObject) delete mediaObject;
1141     if (audioOutput) delete audioOutput;
1142     mediaObject = new Phonon::MediaObject(this);
1143     mediaObject->setTickInterval(100);
1144     connect(mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
1145             this, SLOT(stateChanged(Phonon::State, Phonon::State)));
1146     connect(mediaObject, SIGNAL(tick(qint64)), this, SLOT(tick(qint64)));
1147     connect(mediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64)));
1148     seekSlider->setMediaObject(mediaObject);
1149     audioOutput = new Phonon::AudioOutput(Phonon::VideoCategory, this);
1150     connect(audioOutput, SIGNAL(volumeChanged(qreal)), this, SLOT(volumeChanged(qreal)));
1151     connect(audioOutput, SIGNAL(mutedChanged(bool)), this, SLOT(volumeMutedChanged(bool)));
1152     volumeSlider->setAudioOutput(audioOutput);
1153     Phonon::createPath(mediaObject, audioOutput);
1154 }
1155
1156 void MainWindow::tick(qint64 time) {
1157     if (time <= 0) {
1158         // the "if" is important because tick is continually called
1159         // and we don't want to paint the toolbar every 100ms
1160         if (!currentTime->text().isEmpty()) currentTime->clear();
1161         return;
1162     }
1163
1164     currentTime->setText(formatTime(time));
1165
1166     // remaining time
1167     const qint64 remainingTime = mediaObject->remainingTime();
1168     currentTime->setStatusTip(tr("Remaining time: %1").arg(formatTime(remainingTime)));
1169
1170     /*
1171     slider->blockSignals(true);
1172     slider->setValue(time/1000);
1173     slider->blockSignals(false);
1174     */
1175 }
1176
1177 void MainWindow::totalTimeChanged(qint64 time) {
1178     if (time <= 0) {
1179         totalTime->clear();
1180         return;
1181     }
1182     totalTime->setText(formatTime(time));
1183
1184     /*
1185     slider->blockSignals(true);
1186     slider->setMaximum(time/1000);
1187     slider->blockSignals(false);
1188     */
1189
1190 }
1191
1192 QString MainWindow::formatTime(qint64 time) {
1193     QTime displayTime;
1194     displayTime = displayTime.addMSecs(time);
1195     QString timeString;
1196     // 60 * 60 * 1000 = 3600000
1197     if (time > 3600000)
1198         timeString = displayTime.toString("h:mm:ss");
1199     else
1200         timeString = displayTime.toString("m:ss");
1201     return timeString;
1202 }
1203
1204 void MainWindow::volumeUp() {
1205     qreal newVolume = volumeSlider->audioOutput()->volume() + .1;
1206     if (newVolume > volumeSlider->maximumVolume())
1207         newVolume = volumeSlider->maximumVolume();
1208     volumeSlider->audioOutput()->setVolume(newVolume);
1209 }
1210
1211 void MainWindow::volumeDown() {
1212     qreal newVolume = volumeSlider->audioOutput()->volume() - .1;
1213     if (newVolume < 0)
1214         newVolume = 0;
1215     volumeSlider->audioOutput()->setVolume(newVolume);
1216 }
1217
1218 void MainWindow::volumeMute() {
1219     volumeSlider->audioOutput()->setMuted(!volumeSlider->audioOutput()->isMuted());
1220 }
1221
1222 void MainWindow::volumeChanged(qreal newVolume) {
1223     // automatically unmute when volume changes
1224     if (volumeSlider->audioOutput()->isMuted())
1225         volumeSlider->audioOutput()->setMuted(false);
1226     statusBar()->showMessage(tr("Volume at %1%").arg((int)(newVolume*100)));
1227 }
1228
1229 void MainWindow::volumeMutedChanged(bool muted) {
1230     if (muted) {
1231         volumeMuteAct->setIcon(QtIconLoader::icon("audio-volume-muted"));
1232         statusBar()->showMessage(tr("Volume is muted"));
1233     } else {
1234         volumeMuteAct->setIcon(QtIconLoader::icon("audio-volume-high"));
1235         statusBar()->showMessage(tr("Volume is unmuted"));
1236     }
1237 }
1238
1239 void MainWindow::setDefinitionMode(QString definitionName) {
1240     QAction *definitionAct = The::globalActions()->value("definition");
1241     definitionAct->setText(definitionName);
1242     definitionAct->setStatusTip(tr("Maximum video definition set to %1").arg(definitionAct->text())
1243                                 + " (" +  definitionAct->shortcut().toString(QKeySequence::NativeText) + ")");
1244     statusBar()->showMessage(definitionAct->statusTip());
1245     QSettings settings;
1246     settings.setValue("definition", definitionName);
1247 }
1248
1249 void MainWindow::toggleDefinitionMode() {
1250     QSettings settings;
1251     QString currentDefinition = settings.value("definition").toString();
1252     QStringList definitionNames = VideoDefinition::getDefinitionNames();
1253     int currentIndex = definitionNames.indexOf(currentDefinition);
1254     int nextIndex = 0;
1255     if (currentIndex != definitionNames.size() - 1) {
1256         nextIndex = currentIndex + 1;
1257     }
1258     QString nextDefinition = definitionNames.at(nextIndex);
1259     setDefinitionMode(nextDefinition);
1260 }
1261
1262 void MainWindow::showFullscreenToolbar(bool show) {
1263     if (!m_fullscreen) return;
1264     mainToolBar->setVisible(show);
1265 }
1266
1267 void MainWindow::showFullscreenPlaylist(bool show) {
1268     if (!m_fullscreen) return;
1269     mediaView->setPlaylistVisible(show);
1270 }
1271
1272 void MainWindow::clearRecentKeywords() {
1273     QSettings settings;
1274     settings.remove("recentKeywords");
1275     settings.remove("recentChannels");
1276     searchView->updateRecentKeywords();
1277     searchView->updateRecentChannels();
1278     statusBar()->showMessage(tr("Your privacy is now safe"));
1279 }
1280
1281 void MainWindow::setManualPlay(bool enabled) {
1282     QSettings settings;
1283     settings.setValue("manualplay", QVariant::fromValue(enabled));
1284     showActionInStatusBar(The::globalActions()->value("manualplay"), enabled);
1285 }
1286
1287 void MainWindow::updateDownloadMessage(QString message) {
1288     The::globalActions()->value("downloads")->setText(message);
1289 }
1290
1291 void MainWindow::downloadsFinished() {
1292     The::globalActions()->value("downloads")->setText(tr("&Downloads"));
1293     statusBar()->showMessage(tr("Downloads complete"));
1294 }
1295
1296 void MainWindow::toggleDownloads(bool show) {
1297
1298     if (show) {
1299         stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_MediaStop));
1300         The::globalActions()->value("downloads")->setShortcuts(
1301                 QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_J)
1302                 << QKeySequence(Qt::Key_Escape));
1303     } else {
1304         The::globalActions()->value("downloads")->setShortcuts(
1305                 QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_J));
1306         stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
1307     }
1308
1309     if (!downloadView) {
1310         downloadView = new DownloadView(this);
1311         views->addWidget(downloadView);
1312     }
1313     if (show) showWidget(downloadView);
1314     else goBack();
1315 }
1316
1317 void MainWindow::startToolbarSearch(QString query) {
1318     query = query.trimmed();
1319
1320     // check for empty query
1321     if (query.length() == 0) {
1322         return;
1323     }
1324
1325     SearchParams *searchParams = new SearchParams();
1326     searchParams->setKeywords(query);
1327
1328     // go!
1329     showMedia(searchParams);
1330 }
1331
1332 void MainWindow::dragEnterEvent(QDragEnterEvent *event) {
1333     if (event->mimeData()->hasFormat("text/uri-list")) {
1334         QList<QUrl> urls = event->mimeData()->urls();
1335         if (urls.isEmpty())
1336             return;
1337         QUrl url = urls.first();
1338         QString videoId = YouTubeSearch::videoIdFromUrl(url.toString());
1339         if (!videoId.isNull())
1340             event->acceptProposedAction();
1341     }
1342 }
1343
1344 void MainWindow::dropEvent(QDropEvent *event) {
1345     QList<QUrl> urls = event->mimeData()->urls();
1346     if (urls.isEmpty())
1347         return;
1348     QUrl url = urls.first();
1349     QString videoId = YouTubeSearch::videoIdFromUrl(url.toString());
1350     if (!videoId.isNull()) {
1351         setWindowTitle(url.toString());
1352         SearchParams *searchParams = new SearchParams();
1353         searchParams->setKeywords(videoId);
1354         showMedia(searchParams);
1355     }
1356 }
1357
1358 void MainWindow::checkForUpdate() {
1359     static const QString updateCheckKey = "updateCheck";
1360
1361     // check every 24h
1362     QSettings settings;
1363     uint unixTime = QDateTime::currentDateTime().toTime_t();
1364     int lastCheck = settings.value(updateCheckKey).toInt();
1365     int secondsSinceLastCheck = unixTime - lastCheck;
1366     // qDebug() << "secondsSinceLastCheck" << unixTime << lastCheck << secondsSinceLastCheck;
1367     if (secondsSinceLastCheck < 86400) return;
1368
1369     // check it out
1370     if (updateChecker) delete updateChecker;
1371     updateChecker = new UpdateChecker();
1372     connect(updateChecker, SIGNAL(newVersion(QString)),
1373             this, SLOT(gotNewVersion(QString)));
1374     updateChecker->checkForUpdate();
1375     settings.setValue(updateCheckKey, unixTime);
1376
1377 }
1378
1379 void MainWindow::gotNewVersion(QString version) {
1380     if (updateChecker) {
1381         delete updateChecker;
1382         updateChecker = 0;
1383     }
1384
1385 #if defined(APP_DEMO) || defined(APP_MAC_STORE) || defined(APP_USC)
1386     return;
1387 #endif
1388
1389     QSettings settings;
1390     QString checkedVersion = settings.value("checkedVersion").toString();
1391     if (checkedVersion == version) return;
1392
1393     QMessageBox msgBox(this);
1394     msgBox.setIconPixmap(QPixmap(":/images/app.png").scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation));
1395     msgBox.setText(tr("%1 version %2 is now available.").arg(Constants::NAME, version));
1396
1397     msgBox.setModal(true);
1398     // make it a "sheet" on the Mac
1399     msgBox.setWindowModality(Qt::WindowModal);
1400
1401     QPushButton* laterButton = 0;
1402     QPushButton* updateButton = 0;
1403
1404 #if defined(APP_MAC) || defined(APP_WIN)
1405     msgBox.setInformativeText(
1406                 tr("To get the updated version, download %1 again from the link you received via email and reinstall.")
1407                 .arg(Constants::NAME)
1408                 );
1409     laterButton = msgBox.addButton(tr("Remind me later"), QMessageBox::RejectRole);
1410     msgBox.addButton(QMessageBox::Ok);
1411 #else
1412     msgBox.addButton(QMessageBox::Close);
1413     updateButton = msgBox.addButton(tr("Update"), QMessageBox::AcceptRole);
1414 #endif
1415
1416     msgBox.exec();
1417
1418     if (msgBox.clickedButton() != laterButton) {
1419         settings.setValue("checkedVersion", version);
1420     }
1421
1422     if (updateButton && msgBox.clickedButton() == updateButton) {
1423         QDesktopServices::openUrl(QUrl(QLatin1String(Constants::WEBSITE) + "#download"));
1424     }
1425
1426 }
1427
1428 void MainWindow::floatOnTop(bool onTop) {
1429     showActionInStatusBar(The::globalActions()->value("ontop"), onTop);
1430 #ifdef APP_MAC
1431     mac::floatOnTop(winId(), onTop);
1432     return;
1433 #endif
1434     if (onTop) {
1435         setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
1436         show();
1437     } else {
1438         setWindowFlags(windowFlags() ^ Qt::WindowStaysOnTopHint);
1439         show();
1440     }
1441 }
1442
1443 void MainWindow::restore() {
1444 #ifdef APP_MAC
1445     mac::uncloseWindow(window()->winId());
1446 #endif
1447 }
1448
1449 void MainWindow::messageReceived(const QString &message) {
1450     if (message == "--toggle-playing") {
1451         if (pauseAct->isEnabled()) pauseAct->trigger();
1452     } else if (message == "--next") {
1453         if (skipAct->isEnabled()) skipAct->trigger();
1454     } else if (message == "--previous") {
1455         if (skipBackwardAct->isEnabled()) skipBackwardAct->trigger();
1456     }  else if (message.startsWith("--")) {
1457         MainWindow::printHelp();
1458     } else if (!message.isEmpty()) {
1459         SearchParams *searchParams = new SearchParams();
1460         searchParams->setKeywords(message);
1461         showMedia(searchParams);
1462     }
1463 }
1464
1465 void MainWindow::hideMouse() {
1466     setCursor(Qt::BlankCursor);
1467     mediaView->setPlaylistVisible(false);
1468 #ifndef APP_MAC
1469     mainToolBar->setVisible(false);
1470 #endif
1471 }
1472
1473 void MainWindow::printHelp() {
1474     QString msg = QString("%1 %2\n\n").arg(Constants::NAME, Constants::VERSION);
1475     msg += "Usage: minitube [options]\n";
1476     msg += "Options:\n";
1477     msg += "  --toggle-playing\t";
1478     msg += "Start or pause playback.\n";
1479     msg += "  --next\t\t";
1480     msg += "Skip to the next video.\n";
1481     msg += "  --previous\t\t";
1482     msg += "Go back to the previous video.\n";
1483     std::cout << msg.toLocal8Bit().data();
1484 }