]> git.sur5r.net Git - minitube/blob - src/MainWindow.cpp
Toolbar follows native style with Qt >= 4.6
[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
7 MainWindow::MainWindow() :
8         mediaObject(0),
9         audioOutput(0),
10         aboutView(0) {
11
12     m_fullscreen = false;
13     
14     // views mechanism
15     history = new QStack<QWidget*>();
16     views = new QStackedWidget(this);
17     
18     // views
19     searchView = new SearchView(this);
20     connect(searchView, SIGNAL(search(QString)), this, SLOT(showMedia(QString)));
21     views->addWidget(searchView);
22     
23     mediaView = new MediaView(this);
24     views->addWidget(mediaView);
25     
26     toolbarSearch = new SearchLineEdit(this);
27     toolbarSearch->setFont(qApp->font());
28     toolbarSearch->setMinimumWidth(toolbarSearch->fontInfo().pixelSize()*15);
29     connect(toolbarSearch, SIGNAL(search(const QString&)), searchView, SLOT(watch(const QString&)));
30     
31     // build ui
32     createActions();
33     createMenus();
34     createToolBars();
35     createStatusBar();
36     
37     initPhonon();
38     mediaView->setMediaObject(mediaObject);
39     
40     // remove that useless menu/toolbar context menu
41     this->setContextMenuPolicy(Qt::NoContextMenu);
42     
43     // mediaView init stuff thats needs actions
44     mediaView->initialize();
45     
46     // restore window position
47     readSettings();
48     
49     // event filter to block ugly toolbar tooltips
50     qApp->installEventFilter(this);
51
52     // show the initial view
53     showWidget(searchView);
54     
55     setCentralWidget(views);
56 }
57
58 MainWindow::~MainWindow() {
59     delete history;
60 }
61
62 bool MainWindow::eventFilter(QObject *obj, QEvent *event) {
63     if (event->type() == QEvent::ToolTip) {
64         // kill tooltips
65         return true;
66     } else {
67         // standard event processing
68         return QObject::eventFilter(obj, event);
69     }
70 }
71
72 void MainWindow::createActions() {
73     
74     QMap<QString, QAction*> *actions = The::globalActions();
75     
76     backAct = new QAction(tr("&Back"), this);
77     backAct->setEnabled(false);
78     backAct->setShortcut(QKeySequence(Qt::ALT + Qt::Key_Left));
79     backAct->setStatusTip(tr("Go to the previous view"));
80     actions->insert("back", backAct);
81     connect(backAct, SIGNAL(triggered()), this, SLOT(goBack()));
82     
83     stopAct = new QAction(QtIconLoader::icon("media-playback-stop", QIcon(":/images/media-playback-stop.png")), tr("&Stop"), this);
84     stopAct->setStatusTip(tr("Stop playback and go back to the search view"));
85     stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
86     actions->insert("stop", stopAct);
87     connect(stopAct, SIGNAL(triggered()), this, SLOT(stop()));
88     
89     skipAct = new QAction(QtIconLoader::icon("media-skip-forward", QIcon(":/images/media-skip-forward.png")), tr("S&kip"), this);
90     skipAct->setStatusTip(tr("Skip to the next video"));
91     skipAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_Right) << QKeySequence(Qt::Key_MediaNext));
92     skipAct->setEnabled(false);
93     actions->insert("skip", skipAct);
94     connect(skipAct, SIGNAL(triggered()), mediaView, SLOT(skip()));
95     
96     pauseAct = new QAction(QtIconLoader::icon("media-playback-pause", QIcon(":/images/media-playback-pause.png")), tr("&Pause"), this);
97     pauseAct->setStatusTip(tr("Pause playback"));
98     pauseAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Space) << QKeySequence(Qt::Key_MediaPlay));
99     pauseAct->setEnabled(false);
100     actions->insert("pause", pauseAct);
101     connect(pauseAct, SIGNAL(triggered()), mediaView, SLOT(pause()));
102     
103     fullscreenAct = new QAction(QtIconLoader::icon("view-fullscreen", QIcon(":/images/view-fullscreen.png")), tr("&Full Screen"), this);
104     fullscreenAct->setStatusTip(tr("Go full screen"));
105     fullscreenAct->setShortcut(QKeySequence(Qt::ALT + Qt::Key_Return));
106     fullscreenAct->setShortcutContext(Qt::ApplicationShortcut);
107     actions->insert("fullscreen", fullscreenAct);
108     connect(fullscreenAct, SIGNAL(triggered()), this, SLOT(fullscreen()));
109     
110     compactViewAct = new QAction(tr("&Compact mode"), this);
111     compactViewAct->setStatusTip(tr("Hide the playlist and the toolbar"));
112     compactViewAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Return));
113     compactViewAct->setCheckable(true);
114     compactViewAct->setChecked(false);
115     compactViewAct->setEnabled(false);
116     actions->insert("compactView", compactViewAct);
117     connect(compactViewAct, SIGNAL(toggled(bool)), this, SLOT(compactView(bool)));
118     
119     webPageAct = new QAction(tr("&YouTube"), this);
120     webPageAct->setStatusTip(tr("Open the YouTube video page"));
121     webPageAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Y));
122     webPageAct->setEnabled(false);
123     actions->insert("webpage", webPageAct);
124     connect(webPageAct, SIGNAL(triggered()), mediaView, SLOT(openWebPage()));
125     
126     removeAct = new QAction(tr("&Remove"), this);
127     removeAct->setStatusTip(tr("Remove the selected videos from the playlist"));
128     removeAct->setShortcuts(QList<QKeySequence>() << QKeySequence("Del") << QKeySequence("Backspace"));
129     removeAct->setEnabled(false);
130     actions->insert("remove", removeAct);
131     connect(removeAct, SIGNAL(triggered()), mediaView, SLOT(removeSelected()));
132     
133     moveUpAct = new QAction(tr("Move &Up"), this);
134     moveUpAct->setStatusTip(tr("Move up the selected videos in the playlist"));
135     moveUpAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Up));
136     moveUpAct->setEnabled(false);
137     actions->insert("moveUp", moveUpAct);
138     connect(moveUpAct, SIGNAL(triggered()), mediaView, SLOT(moveUpSelected()));
139     
140     moveDownAct = new QAction(tr("Move &Down"), this);
141     moveDownAct->setStatusTip(tr("Move down the selected videos in the playlist"));
142     moveDownAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Down));
143     moveDownAct->setEnabled(false);
144     actions->insert("moveDown", moveDownAct);
145     connect(moveDownAct, SIGNAL(triggered()), mediaView, SLOT(moveDownSelected()));
146
147     clearAct = new QAction(tr("&Clear recent keywords"), this);
148     clearAct->setMenuRole(QAction::ApplicationSpecificRole);
149     clearAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Delete) << QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Backspace));
150     clearAct->setEnabled(true);
151     actions->insert("clearRecentKeywords", clearAct);
152     connect(clearAct, SIGNAL(triggered()), searchView, SLOT(clearRecentKeywords()));
153
154     quitAct = new QAction(tr("&Quit"), this);
155     quitAct->setMenuRole(QAction::QuitRole);
156     quitAct->setShortcuts(QList<QKeySequence>() << QKeySequence(tr("Ctrl+Q")) << QKeySequence(Qt::CTRL + Qt::Key_W));
157     quitAct->setStatusTip(tr("Bye"));
158     actions->insert("quit", quitAct);
159     connect(quitAct, SIGNAL(triggered()), this, SLOT(quit()));
160     
161     siteAct = new QAction(tr("&Website"), this);
162     siteAct->setShortcut(QKeySequence::HelpContents);
163     siteAct->setStatusTip(tr("%1 on the Web").arg(Constants::APP_NAME));
164     actions->insert("site", siteAct);
165     connect(siteAct, SIGNAL(triggered()), this, SLOT(visitSite()));
166     
167     donateAct = new QAction(tr("&Donate via PayPal"), this);
168     donateAct->setStatusTip(tr("Please support the continued development of %1").arg(Constants::APP_NAME));
169     actions->insert("donate", donateAct);
170     connect(donateAct, SIGNAL(triggered()), this, SLOT(donate()));
171     
172     aboutAct = new QAction(tr("&About"), this);
173     aboutAct->setMenuRole(QAction::AboutRole);
174     aboutAct->setStatusTip(tr("Info about %1").arg(Constants::APP_NAME));
175     actions->insert("about", aboutAct);
176     connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
177     
178     // Invisible actions
179     
180     searchFocusAct = new QAction(this);
181     searchFocusAct->setShortcut(QKeySequence::Find);
182     searchFocusAct->setStatusTip(tr("Search"));
183     actions->insert("search", searchFocusAct);
184     connect(searchFocusAct, SIGNAL(triggered()), this, SLOT(searchFocus()));
185     addAction(searchFocusAct);
186     
187     volumeUpAct = new QAction(this);
188     volumeUpAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_Plus) << QKeySequence(Qt::Key_VolumeUp));
189     actions->insert("volume-up", volumeUpAct);
190     connect(volumeUpAct, SIGNAL(triggered()), this, SLOT(volumeUp()));
191     addAction(volumeUpAct);
192     
193     volumeDownAct = new QAction(this);
194     volumeDownAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_Minus) << QKeySequence(Qt::Key_VolumeDown));
195     actions->insert("volume-down", volumeDownAct);
196     connect(volumeDownAct, SIGNAL(triggered()), this, SLOT(volumeDown()));
197     addAction(volumeDownAct);
198     
199     volumeMuteAct = new QAction(this);
200     volumeMuteAct->setStatusTip(tr("Mute volume"));
201     volumeMuteAct->setShortcuts(QList<QKeySequence>() << QKeySequence(tr("Ctrl+M")) << QKeySequence(Qt::Key_VolumeMute));
202     actions->insert("volume-mute", volumeMuteAct);
203     connect(volumeMuteAct, SIGNAL(triggered()), this, SLOT(volumeMute()));
204     addAction(volumeMuteAct);
205     
206     QAction *hdAct = new QAction(this);
207     hdAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_D));
208     hdAct->setIcon(createHDIcon());
209     hdAct->setCheckable(true);
210     actions->insert("hd", hdAct);
211     connect(hdAct, SIGNAL(toggled(bool)), this, SLOT(hdMode(bool)));
212     addAction(hdAct);
213     
214     // common action properties
215     foreach (QAction *action, actions->values()) {
216         
217         // add actions to the MainWindow so that they work
218         // when the menu is hidden
219         addAction(action);
220         
221         // never autorepeat.
222         // unexperienced users tend to keep keys pressed for a "long" time
223         action->setAutoRepeat(false);
224         
225         // set to something more meaningful then the toolbar text
226         // HELP! how to remove tooltips altogether?!
227         if (!action->statusTip().isEmpty())
228             action->setToolTip(action->statusTip());
229         
230         // show keyboard shortcuts in the status bar
231         if (!action->shortcut().isEmpty())
232             action->setStatusTip(action->statusTip() + " (" + action->shortcut().toString(QKeySequence::NativeText) + ")");
233
234         // no icons in menus
235         action->setIconVisibleInMenu(false);
236         
237     }
238     
239 }
240
241 void MainWindow::createMenus() {
242     
243     QMap<QString, QMenu*> *menus = The::globalMenus();
244
245     fileMenu = menuBar()->addMenu(tr("&Application"));
246     // menus->insert("file", fileMenu);
247     fileMenu->addAction(clearAct);
248 #ifndef Q_WS_MAC
249     fileMenu->addSeparator();
250 #endif
251     fileMenu->addAction(quitAct);
252
253     playlistMenu = menuBar()->addMenu(tr("&Playlist"));
254     menus->insert("playlist", playlistMenu);
255     playlistMenu->addAction(removeAct);
256     playlistMenu->addSeparator();
257     playlistMenu->addAction(moveUpAct);
258     playlistMenu->addAction(moveDownAct);
259     
260     viewMenu = menuBar()->addMenu(tr("&Video"));
261     menus->insert("video", viewMenu);
262     // viewMenu->addAction(backAct);
263     viewMenu->addAction(stopAct);
264     viewMenu->addAction(pauseAct);
265     viewMenu->addAction(skipAct);
266     viewMenu->addSeparator();
267     viewMenu->addAction(webPageAct);
268     viewMenu->addSeparator();
269     // viewMenu->addAction(downloadAct);
270     viewMenu->addAction(compactViewAct);
271     viewMenu->addAction(fullscreenAct);
272     
273     helpMenu = menuBar()->addMenu(tr("&Help"));
274     helpMenu->addAction(siteAct);
275     helpMenu->addAction(donateAct);
276     helpMenu->addAction(aboutAct);
277 }
278
279 void MainWindow::createToolBars() {
280     
281     mainToolBar = new QToolBar(this);
282 #if QT_VERSION < 0x040600
283     mainToolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
284 #else
285     mainToolBar->setToolButtonStyle(Qt::ToolButtonFollowStyle);
286 #endif
287     mainToolBar->setFloatable(false);
288     mainToolBar->setMovable(false);
289     // cool toolbar on the Mac
290     // setUnifiedTitleAndToolBarOnMac(true);
291     
292     QFont smallerFont;
293     smallerFont.setPointSize(smallerFont.pointSize()*.85);
294     QFontInfo fontInfo(smallerFont);
295     if (fontInfo.pixelSize() < 10) {
296         smallerFont.setPixelSize(10);
297     }
298     mainToolBar->setFont(smallerFont);
299     
300     mainToolBar->setIconSize(QSize(32,32));
301     // mainToolBar->addAction(backAct);
302     mainToolBar->addAction(stopAct);
303     mainToolBar->addAction(pauseAct);
304     mainToolBar->addAction(skipAct);
305     mainToolBar->addAction(fullscreenAct);
306     
307     seekSlider = new Phonon::SeekSlider(this);
308     seekSlider->setIconVisible(false);
309     Spacer *seekSliderSpacer = new Spacer(mainToolBar, seekSlider);
310     seekSliderSpacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
311     mainToolBar->addWidget(seekSliderSpacer);
312     
313     volumeSlider = new Phonon::VolumeSlider(this);
314     // qDebug() << volumeSlider->children();
315     // status tip for the volume slider
316     QSlider* volumeQSlider = volumeSlider->findChild<QSlider*>();
317     if (volumeQSlider)
318         volumeQSlider->setStatusTip(tr("Press %1 to raise the volume, %2 to lower it").arg(
319                 volumeUpAct->shortcut().toString(QKeySequence::NativeText), volumeDownAct->shortcut().toString(QKeySequence::NativeText)));
320     // status tip for the mute button
321     QToolButton* muteToolButton = volumeSlider->findChild<QToolButton*>();
322     if (muteToolButton)
323         muteToolButton->setStatusTip(volumeMuteAct->statusTip());
324     // this makes the volume slider smaller
325     volumeSlider->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
326     mainToolBar->addWidget(new Spacer(mainToolBar, volumeSlider));
327     
328     toolbarSearch->setStatusTip(searchFocusAct->statusTip());
329     mainToolBar->addWidget(new Spacer(mainToolBar, toolbarSearch));
330     
331     addToolBar(mainToolBar);
332 }
333
334 void MainWindow::createStatusBar() {
335     currentTime = new QLabel(this);
336     statusBar()->addPermanentWidget(currentTime);
337     
338     totalTime = new QLabel(this);
339     statusBar()->addPermanentWidget(totalTime);
340     
341     // remove ugly borders on OSX
342     // and remove some excessive padding
343     statusBar()->setStyleSheet("::item{border:0 solid} "
344                                "QStatusBar, QToolBar, QToolButton {spacing:0;padding:0;margin:0} "
345                                );
346     
347     QToolBar *toolBar = new QToolBar(this);
348     int iconHeight = 24; // statusBar()->height();
349     int iconWidth = 36; // iconHeight * 3 / 2;
350     toolBar->setIconSize(QSize(iconWidth, iconHeight));
351     toolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
352     toolBar->addAction(The::globalActions()->value("hd"));
353     statusBar()->addPermanentWidget(toolBar);
354     
355     statusBar()->show();
356 }
357
358 void MainWindow::readSettings() {
359     QSettings settings;
360     restoreGeometry(settings.value("geometry").toByteArray());
361     hdMode(settings.value("hd").toBool());
362     audioOutput->setVolume(settings.value("volume", 1).toDouble());
363     audioOutput->setMuted(settings.value("volumeMute").toBool());
364 }
365
366 void MainWindow::writeSettings() {
367     // do not save geometry when in full screen
368     if (m_fullscreen)
369         return;
370     QSettings settings;
371     settings.setValue("geometry", saveGeometry());
372     settings.setValue("hd", The::globalActions()->value("hd")->isChecked());
373     settings.setValue("volume", audioOutput->volume());
374     settings.setValue("volumeMute", audioOutput->isMuted());
375     mediaView->saveSplitterState();
376 }
377
378 void MainWindow::goBack() {
379     if ( history->size() > 1 ) {
380         history->pop();
381         QWidget *widget = history->pop();
382         showWidget(widget);
383     }
384 }
385
386 void MainWindow::showWidget ( QWidget* widget ) {
387     
388     setUpdatesEnabled(false);
389     
390     // call hide method on the current view
391     View* oldView = dynamic_cast<View *> (views->currentWidget());
392     if (oldView) {
393         oldView->disappear();
394     }
395     
396     // call show method on the new view
397     View* newView = dynamic_cast<View *> (widget);
398     if (newView) {
399         newView->appear();
400         QMap<QString,QVariant> metadata = newView->metadata();
401         QString windowTitle = metadata.value("title").toString();
402         if (windowTitle.length())
403             windowTitle += " - ";
404         setWindowTitle(windowTitle + Constants::APP_NAME);
405         statusBar()->showMessage((metadata.value("description").toString()));
406     }
407     
408     // backAct->setEnabled(history->size() > 1);
409     stopAct->setEnabled(widget == mediaView);
410     fullscreenAct->setEnabled(widget == mediaView);
411     compactViewAct->setEnabled(widget == mediaView);
412     webPageAct->setEnabled(widget == mediaView);    
413     aboutAct->setEnabled(widget != aboutView);
414
415     // toolbar only for the mediaView
416     mainToolBar->setVisible(widget == mediaView && !compactViewAct->isChecked());
417
418     setUpdatesEnabled(true);
419     
420     QWidget *oldWidget = views->currentWidget();
421     views->setCurrentWidget(widget);
422     
423 #ifdef Q_WS_MAC
424     // crossfade only on OSX
425     // where we can be sure of video performance
426     fadeInWidget(oldWidget, widget);
427 #endif
428     
429     history->push(widget);
430 }
431
432 void MainWindow::fadeInWidget(QWidget *oldWidget, QWidget *newWidget) {
433     if (faderWidget) faderWidget->close();
434     if (!oldWidget || !newWidget) {
435         // qDebug() << "no widgets";
436         return;
437     }
438     faderWidget = new FaderWidget(newWidget);
439     faderWidget->start(QPixmap::grabWidget(oldWidget));
440 }
441
442 void MainWindow::about() {
443     if (!aboutView) {
444         aboutView = new AboutView(this);
445         views->addWidget(aboutView);
446     }
447     showWidget(aboutView);
448 }
449
450 void MainWindow::visitSite() {
451     QUrl url(Constants::WEBSITE);
452     statusBar()->showMessage(QString(tr("Opening %1").arg(url.toString())));
453     QDesktopServices::openUrl(url);
454 }
455
456 void MainWindow::donate() {
457     QUrl url(QString(Constants::WEBSITE) + "#donate");
458     statusBar()->showMessage(QString(tr("Opening %1").arg(url.toString())));
459     QDesktopServices::openUrl(url);
460 }
461
462 void MainWindow::quit() {
463     writeSettings();
464     qApp->quit();
465 }
466
467 void MainWindow::closeEvent(QCloseEvent *event) {
468     quit();
469     QWidget::closeEvent(event);
470 }
471
472 /*
473 void MainWindow::showSettings() {
474     if (!settingsView) {
475         settingsView = new SettingsView(this);
476         views->addWidget(settingsView);
477     }
478     showWidget(settingsView);
479 }*/
480
481 void MainWindow::showSearch() {
482     showWidget(searchView);
483     currentTime->clear();
484     totalTime->clear();
485 }
486
487 void MainWindow::showMedia(QString query) {
488     SearchParams *searchParams = new SearchParams();
489     searchParams->setKeywords(query);
490     mediaView->search(searchParams);
491     showWidget(mediaView);
492 }
493
494 void MainWindow::stateChanged(Phonon::State newState, Phonon::State /* oldState */) {
495     
496     // qDebug() << "Phonon state: " << newState;
497     
498     switch (newState) {
499         
500     case Phonon::ErrorState:
501         if (mediaObject->errorType() == Phonon::FatalError) {
502             statusBar()->showMessage(tr("Fatal error: %1").arg(mediaObject->errorString()));
503         } else {
504             statusBar()->showMessage(tr("Error: %1").arg(mediaObject->errorString()));
505         }
506         break;
507         
508          case Phonon::PlayingState:
509         pauseAct->setEnabled(true);
510         pauseAct->setIcon(QtIconLoader::icon("media-playback-pause", QIcon(":/images/media-playback-pause.png")));
511         pauseAct->setText(tr("&Pause"));
512         pauseAct->setStatusTip(tr("Pause playback") + " (" +  pauseAct->shortcut().toString(QKeySequence::NativeText) + ")");
513         skipAct->setEnabled(true);
514         break;
515         
516          case Phonon::StoppedState:
517         pauseAct->setEnabled(false);
518         skipAct->setEnabled(false);
519         break;
520         
521          case Phonon::PausedState:
522         skipAct->setEnabled(true);
523         pauseAct->setEnabled(true);
524         pauseAct->setIcon(QtIconLoader::icon("media-playback-start", QIcon(":/images/media-playback-start.png")));
525         pauseAct->setText(tr("&Play"));
526         pauseAct->setStatusTip(tr("Resume playback") + " (" +  pauseAct->shortcut().toString(QKeySequence::NativeText) + ")");
527         break;
528         
529          case Phonon::BufferingState:
530          case Phonon::LoadingState:
531         skipAct->setEnabled(true);
532         pauseAct->setEnabled(false);
533         currentTime->clear();
534         totalTime->clear();
535         break;
536         
537          default:
538         ;
539     }
540 }
541
542 void MainWindow::stop() {
543     mediaView->stop();
544     showSearch();
545 }
546
547 void MainWindow::fullscreen() {
548     
549     setUpdatesEnabled(false);
550     
551     if (m_fullscreen) {
552         // use setShortucs instead of setShortcut
553         // the latter seems not to work
554         fullscreenAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::ALT + Qt::Key_Return));
555         fullscreenAct->setText(tr("&Full Screen"));
556         stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
557         if (m_maximized) showMaximized();
558         else showNormal();
559         // Make sure the window has focus (Mac)
560         activateWindow();
561     } else {
562         stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_MediaStop));
563         fullscreenAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::ALT + Qt::Key_Return));
564         fullscreenAct->setText(tr("Exit &Full Screen"));
565         m_maximized = isMaximized();
566         
567         // save geometry now, if the user quits when in full screen
568         // geometry won't be saved
569         writeSettings();
570         
571         showFullScreen();
572     }
573     
574     // No compact view action when in full screen
575     compactViewAct->setVisible(m_fullscreen);
576     compactViewAct->setChecked(false);
577     
578     // Also no Youtube action since it opens a new window
579     webPageAct->setVisible(m_fullscreen);
580     stopAct->setVisible(m_fullscreen);
581     
582     // Hide anything but the video
583     mediaView->setPlaylistVisible(m_fullscreen);
584     mainToolBar->setVisible(m_fullscreen);
585     statusBar()->setVisible(m_fullscreen);
586     menuBar()->setVisible(m_fullscreen);
587     
588     // workaround: prevent focus on the search bar
589     // it steals the Space key needed for Play/Pause
590     mainToolBar->setEnabled(m_fullscreen);
591
592 #ifdef Q_WS_MAC
593     // make the actions work when video is fullscreen (on the Mac)
594     QMap<QString, QAction*> *actions = The::globalActions();
595     foreach (QAction *action, actions->values()) {
596         if (m_fullscreen) {
597             action->setShortcutContext(Qt::WindowShortcut);
598         } else {
599             action->setShortcutContext(Qt::ApplicationShortcut);
600         }
601     }
602 #endif
603
604     m_fullscreen = !m_fullscreen;
605
606     setUpdatesEnabled(true);
607 }
608
609 void MainWindow::compactView(bool enable) {
610     
611     setUpdatesEnabled(false);
612     
613     // setUnifiedTitleAndToolBarOnMac(!enable);
614     mediaView->setPlaylistVisible(!enable);
615     mainToolBar->setVisible(!enable);
616     statusBar()->setVisible(!enable);
617     menuBar()->setVisible(!enable);
618
619     // ensure focus does not end up to the search box
620     // as it would steal the Space shortcut
621     toolbarSearch->setEnabled(!enable);
622     
623     if (enable) {
624         stopAct->setShortcut(QString(""));
625         QList<QKeySequence> shortcuts;
626         // for some reason it is important that ESC comes first
627         shortcuts << QKeySequence(Qt::CTRL + Qt::Key_Return) << QKeySequence(Qt::Key_Escape);
628         compactViewAct->setShortcuts(shortcuts);
629     } else {
630         compactViewAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Return));
631         stopAct->setShortcut(QKeySequence(Qt::Key_Escape));
632     }
633
634     setUpdatesEnabled(true);
635 }
636
637 void MainWindow::searchFocus() {
638     QWidget *view = views->currentWidget();
639     if (view == mediaView) {
640         toolbarSearch->selectAll();
641         toolbarSearch->setFocus();
642     }
643 }
644
645 void MainWindow::initPhonon() {
646     // Phonon initialization
647     if (mediaObject) delete mediaObject;
648     if (audioOutput) delete audioOutput;
649     mediaObject = new Phonon::MediaObject(this);
650     mediaObject->setTickInterval(100);
651     connect(mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
652             this, SLOT(stateChanged(Phonon::State, Phonon::State)));
653     connect(mediaObject, SIGNAL(tick(qint64)), this, SLOT(tick(qint64)));
654     connect(mediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64)));
655     seekSlider->setMediaObject(mediaObject);
656     audioOutput = new Phonon::AudioOutput(Phonon::VideoCategory, this);
657     connect(audioOutput, SIGNAL(volumeChanged(qreal)), this, SLOT(volumeChanged(qreal)));
658     connect(audioOutput, SIGNAL(mutedChanged(bool)), this, SLOT(volumeMutedChanged(bool)));
659     volumeSlider->setAudioOutput(audioOutput);
660     Phonon::createPath(mediaObject, audioOutput);
661 }
662
663 void MainWindow::tick(qint64 time) {
664     if (time <= 0) {
665         currentTime->clear();
666         return;
667     }
668
669     currentTime->setText(formatTime(time));
670
671     // remaining time
672     const qint64 remainingTime = mediaObject->remainingTime();
673     currentTime->setStatusTip(tr("Remaining time: %1").arg(formatTime(remainingTime)));
674
675 }
676
677 void MainWindow::totalTimeChanged(qint64 time) {
678     if (time <= 0) {
679         totalTime->clear();
680         return;
681     }
682     totalTime->setText("/ " + formatTime(time));
683 }
684
685 QString MainWindow::formatTime(qint64 time) {
686     QTime displayTime;
687     displayTime = displayTime.addMSecs(time);
688     QString timeString;
689     // 60 * 60 * 1000 = 3600000
690     if (time > 3600000)
691         timeString = displayTime.toString("h:mm:ss");
692     else
693         timeString = displayTime.toString("m:ss");
694     return timeString;
695 }
696
697 void MainWindow::volumeUp() {
698     qreal newVolume = volumeSlider->audioOutput()->volume() + .1;
699     if (newVolume > volumeSlider->maximumVolume())
700         newVolume = volumeSlider->maximumVolume();
701     volumeSlider->audioOutput()->setVolume(newVolume);
702 }
703
704 void MainWindow::volumeDown() {
705     qreal newVolume = volumeSlider->audioOutput()->volume() - .1;
706     if (newVolume < 0)
707         newVolume = 0;
708     volumeSlider->audioOutput()->setVolume(newVolume);
709 }
710
711 void MainWindow::volumeMute() {
712     volumeSlider->audioOutput()->setMuted(!volumeSlider->audioOutput()->isMuted());
713 }
714
715 void MainWindow::volumeChanged(qreal newVolume) {
716     // automatically unmute when volume changes
717     if (volumeSlider->audioOutput()->isMuted())
718         volumeSlider->audioOutput()->setMuted(false);
719     statusBar()->showMessage(tr("Volume at %1%").arg(newVolume*100));
720 }
721
722 void MainWindow::volumeMutedChanged(bool muted) {
723     if (muted)
724         statusBar()->showMessage(tr("Volume is muted"));
725     else
726         statusBar()->showMessage(tr("Volume is unmuted"));
727 }
728
729 QPixmap MainWindow::createHDPixmap(bool enabled) {
730     QPixmap pixmap = QPixmap(24,24);
731     pixmap.fill(Qt::transparent);
732     QPainter painter(&pixmap);
733     painter.setRenderHints(QPainter::Antialiasing, true);
734     
735     QRect rect(0, 3, 24, 18);
736     
737     QPen pen;
738     pen.setColor(Qt::black);
739     pen.setWidth(1);
740     painter.setPen(pen);
741     
742     if (enabled) {
743         painter.setBrush(palette().highlight());
744     } else {
745         QLinearGradient gradient(QPointF(0, 0), QPointF(0, rect.height() / 2));
746         gradient.setColorAt(0, QColor(0x6d, 0x6d, 0x6d));
747         gradient.setColorAt(1, QColor(0x25, 0x25, 0x25));
748         painter.setBrush(QBrush(gradient));
749     }
750     painter.drawRoundedRect(rect, 5, 5);
751     
752     if (enabled) {
753         pen.setColor(palette().highlightedText().color());
754     } else {
755         pen.setColor(Qt::white);
756     }
757     painter.setPen(pen);
758     
759     QFont font;
760     font.setPixelSize(12);
761     font.setBold(true);
762     painter.setFont(font);
763     painter.drawText(rect, Qt::AlignCenter, "HD");
764     
765     return pixmap;
766 }
767
768 static QIcon hdOnIcon;
769 static QIcon hdOffIcon;
770
771 QIcon MainWindow::createHDIcon() {
772     hdOffIcon.addPixmap(createHDPixmap(false));
773     hdOnIcon.addPixmap(createHDPixmap(true));
774     return hdOffIcon;
775 }
776
777 void MainWindow::hdMode(bool enabled) {
778     QAction *hdAct = The::globalActions()->value("hd");
779     hdAct->setChecked(enabled);
780     if (enabled) {
781         hdAct->setStatusTip(tr("High Definition video is enabled") + " (" +  hdAct->shortcut().toString(QKeySequence::NativeText) + ")");
782     } else {
783         hdAct->setStatusTip(tr("High Definition video is not enabled") + " (" +  hdAct->shortcut().toString(QKeySequence::NativeText) + ")");
784     }
785     statusBar()->showMessage(hdAct->statusTip());
786     QSettings settings;
787     settings.setValue("hd", enabled);
788 }
789
790 void MainWindow::hdIndicator(bool isHd) {
791     QAction *hdAct = The::globalActions()->value("hd");
792     if (isHd) {
793         hdAct->setIcon(hdOnIcon);
794         hdAct->setToolTip(tr("The current video is in High Definition"));
795     } else {
796         hdAct->setIcon(hdOffIcon);
797         hdAct->setToolTip(tr("The current video is not in High Definition"));
798     }
799 }
800
801 void MainWindow::showFullscreenToolbar(bool show) {
802     if (!m_fullscreen) return;
803
804     if (show) {
805         mainToolBar->show();
806     } else {
807         mainToolBar->hide();
808     }
809     mainToolBar->setEnabled(show);
810 }
811
812 void MainWindow::showFullscreenPlaylist(bool show) {
813     if (!m_fullscreen) return;    
814     mediaView->setPlaylistVisible(show);
815 }
816