]> git.sur5r.net Git - minitube/blobdiff - src/MainWindow.cpp
Updated translations
[minitube] / src / MainWindow.cpp
index 692ff462257bcd2955d92f7e819ff2da6de8a379..c87c398be0d84b2e8d7c7be7362441f510d65d32 100755 (executable)
@@ -1,33 +1,41 @@
 #include "MainWindow.h"
 #include "spacer.h"
-#include "Constants.h"
+#include "constants.h"
 #include "iconloader/qticonloader.h"
 #include "global.h"
+#include "videodefinition.h"
+#include "fontutils.h"
+#include "globalshortcuts.h"
+#ifdef Q_WS_X11
+#include "gnomeglobalshortcutbackend.h"
+#endif
+#ifdef APP_MAC
+// #include "local/mac/mac_startup.h"
+#endif
+#include "downloadmanager.h"
 
-MainWindow::MainWindow() {
-
-    m_fullscreen = false;
-    mediaObject = 0;
-    audioOutput = 0;
+MainWindow::MainWindow() :
+        aboutView(0),
+        downloadView(0),
+        mediaObject(0),
+        audioOutput(0),
+        m_fullscreen(false) {
 
     // views mechanism
     history = new QStack<QWidget*>();
     views = new QStackedWidget(this);
+    setCentralWidget(views);
 
     // views
     searchView = new SearchView(this);
     connect(searchView, SIGNAL(search(QString)), this, SLOT(showMedia(QString)));
     views->addWidget(searchView);
+
     mediaView = new MediaView(this);
     views->addWidget(mediaView);
 
-    // lazy initialized views
-    aboutView = 0;
-    settingsView = 0;
-
     toolbarSearch = new SearchLineEdit(this);
-    toolbarSearch->setFont(qApp->font());
-    // toolbarSearch->setMinimumWidth(200);
+    toolbarSearch->setMinimumWidth(toolbarSearch->fontInfo().pixelSize()*15);
     connect(toolbarSearch, SIGNAL(search(const QString&)), searchView, SLOT(watch(const QString&)));
 
     // build ui
@@ -36,87 +44,89 @@ MainWindow::MainWindow() {
     createToolBars();
     createStatusBar();
 
+    initPhonon();
+    mediaView->setMediaObject(mediaObject);
+
     // remove that useless menu/toolbar context menu
     this->setContextMenuPolicy(Qt::NoContextMenu);
 
     // mediaView init stuff thats needs actions
     mediaView->initialize();
 
+    // event filter to block ugly toolbar tooltips
+    qApp->installEventFilter(this);
+
     // restore window position
     readSettings();
 
     // show the initial view
     showWidget(searchView);
 
-    setCentralWidget(views);
-
-    // top dock widget
-    /*
-    QLabel* message = new QLabel(this);
-    message->setText(QString("A new version of %1 is available.").arg(Constants::APP_NAME));
-    message->setMargin(10);
-    message->setAlignment(Qt::AlignCenter);
-    QPalette palette;
-    message->setBackgroundRole(QPalette::ToolTipBase);
-    message->setForegroundRole(QPalette::ToolTipText);
-    message->setAutoFillBackground(true);
-    QDockWidget *dockWidget = new QDockWidget("", this, 0);
-    dockWidget->setTitleBarWidget(0);
-    dockWidget->setWidget(message);
-    dockWidget->setFeatures(QDockWidget::DockWidgetClosable);
-    addDockWidget(Qt::TopDockWidgetArea, dockWidget);
-    */
-
+    // Global shortcuts
+    GlobalShortcuts &shortcuts = GlobalShortcuts::instance();
+#ifdef Q_WS_X11
+    if (GnomeGlobalShortcutBackend::IsGsdAvailable())
+        shortcuts.setBackend(new GnomeGlobalShortcutBackend(&shortcuts));
+#endif
+#ifdef APP_MAC
+    // mac::MacSetup();
+#endif
+    connect(&shortcuts, SIGNAL(PlayPause()), pauseAct, SLOT(trigger()));
+    connect(&shortcuts, SIGNAL(Stop()), this, SLOT(stop()));
+    connect(&shortcuts, SIGNAL(Next()), skipAct, SLOT(trigger()));
+
+    connect(DownloadManager::instance(), SIGNAL(statusMessageChanged(QString)),
+            SLOT(updateDownloadMessage(QString)));
+    connect(DownloadManager::instance(), SIGNAL(finished()),
+            SLOT(downloadsFinished()));
 }
 
 MainWindow::~MainWindow() {
     delete history;
 }
 
+bool MainWindow::eventFilter(QObject *obj, QEvent *event) {
+    if (event->type() == QEvent::ToolTip) {
+        // kill tooltips
+        return true;
+    } else {
+        // standard event processing
+        return QObject::eventFilter(obj, event);
+    }
+}
+
 void MainWindow::createActions() {
 
     QMap<QString, QAction*> *actions = The::globalActions();
 
-    /*
-    settingsAct = new QAction(tr("&Preferences..."), this);
-    settingsAct->setStatusTip(tr(QString("Configure ").append(Constants::APP_NAME).toUtf8()));
-    // Mac integration
-    settingsAct->setMenuRole(QAction::PreferencesRole);
-    actions->insert("settings", settingsAct);
-    connect(settingsAct, SIGNAL(triggered()), this, SLOT(showSettings()));
-    */
-    
-    backAct = new QAction(QIcon(":/images/go-previous.png"), tr("&Back"), this);
-    backAct->setEnabled(false);
-    backAct->setShortcut(QKeySequence(Qt::ALT + Qt::Key_Left));
-    backAct->setStatusTip(tr("Go to the previous view"));
-    actions->insert("back", backAct);
-    connect(backAct, SIGNAL(triggered()), this, SLOT(goBack()));
-
-    stopAct = new QAction(QtIconLoader::icon("media-stop", QIcon(":/images/stop.png")), tr("&Stop"), this);
+    stopAct = new QAction(QtIconLoader::icon("media-playback-stop"), tr("&Stop"), this);
     stopAct->setStatusTip(tr("Stop playback and go back to the search view"));
-    stopAct->setShortcut(QKeySequence(Qt::Key_Escape));
+    stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
+    stopAct->setEnabled(false);
     actions->insert("stop", stopAct);
     connect(stopAct, SIGNAL(triggered()), this, SLOT(stop()));
 
-    skipAct = new QAction(QtIconLoader::icon("media-skip-forward", QIcon(":/images/skip.png")), tr("S&kip"), this);
+    skipAct = new QAction(QtIconLoader::icon("media-skip-forward"), tr("S&kip"), this);
     skipAct->setStatusTip(tr("Skip to the next video"));
-    skipAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Right));
+    skipAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_Right) << QKeySequence(Qt::Key_MediaNext));
     skipAct->setEnabled(false);
     actions->insert("skip", skipAct);
     connect(skipAct, SIGNAL(triggered()), mediaView, SLOT(skip()));
 
-    pauseAct = new QAction(QtIconLoader::icon("media-pause", QIcon(":/images/pause.png")), tr("&Pause"), this);
+    pauseAct = new QAction(QtIconLoader::icon("media-playback-pause"), tr("&Pause"), this);
     pauseAct->setStatusTip(tr("Pause playback"));
-    pauseAct->setShortcut(QKeySequence(Qt::Key_Space));
+    pauseAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Space) << QKeySequence(Qt::Key_MediaPlay));
     pauseAct->setEnabled(false);
     actions->insert("pause", pauseAct);
     connect(pauseAct, SIGNAL(triggered()), mediaView, SLOT(pause()));
 
-    fullscreenAct = new QAction(QtIconLoader::icon("view-fullscreen", QIcon(":/images/view-fullscreen.png")), tr("&Full Screen"), this);
+    fullscreenAct = new QAction(QtIconLoader::icon("view-fullscreen"), tr("&Full Screen"), this);
     fullscreenAct->setStatusTip(tr("Go full screen"));
     fullscreenAct->setShortcut(QKeySequence(Qt::ALT + Qt::Key_Return));
     fullscreenAct->setShortcutContext(Qt::ApplicationShortcut);
+#if QT_VERSION >= 0x040600
+    fullscreenAct->setPriority(QAction::LowPriority);
+#endif
     actions->insert("fullscreen", fullscreenAct);
     connect(fullscreenAct, SIGNAL(triggered()), this, SLOT(fullscreen()));
 
@@ -129,51 +139,64 @@ void MainWindow::createActions() {
     actions->insert("compactView", compactViewAct);
     connect(compactViewAct, SIGNAL(toggled(bool)), this, SLOT(compactView(bool)));
 
-    /*
-    // icon should be document-save but it is ugly
-    downloadAct = new QAction(QtIconLoader::icon("go-down", QIcon(":/images/go-down.png")), tr("&Download"), this);
-    downloadAct->setStatusTip(tr("Download this video"));
-    downloadAct->setShortcut(tr("Ctrl+S"));
-    actions.insert("download", downloadAct);
-    connect(downloadAct, SIGNAL(triggered()), this, SLOT(download()));
-    */
-
-    webPageAct = new QAction(QtIconLoader::icon("internet-web-browser", QIcon(":/images/internet-web-browser.png")), tr("&YouTube"), this);
-    webPageAct->setStatusTip(tr("Open the YouTube video page"));
+    webPageAct = new QAction(tr("Open the &YouTube page"), this);
+    webPageAct->setStatusTip(tr("Go to the YouTube video page and pause playback"));
     webPageAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Y));
     webPageAct->setEnabled(false);
     actions->insert("webpage", webPageAct);
     connect(webPageAct, SIGNAL(triggered()), mediaView, SLOT(openWebPage()));
 
+    copyPageAct = new QAction(tr("Copy the YouTube &link"), this);
+    copyPageAct->setStatusTip(tr("Copy the current video YouTube link to the clipboard"));
+    copyPageAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_L));
+    copyPageAct->setEnabled(false);
+    actions->insert("pagelink", copyPageAct);
+    connect(copyPageAct, SIGNAL(triggered()), mediaView, SLOT(copyWebPage()));
+
+    copyLinkAct = new QAction(tr("Copy the video stream &URL"), this);
+    copyLinkAct->setStatusTip(tr("Copy the current video stream URL to the clipboard"));
+    copyLinkAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_U));
+    copyLinkAct->setEnabled(false);
+    actions->insert("videolink", copyLinkAct);
+    connect(copyLinkAct, SIGNAL(triggered()), mediaView, SLOT(copyVideoLink()));
+
     removeAct = new QAction(tr("&Remove"), this);
     removeAct->setStatusTip(tr("Remove the selected videos from the playlist"));
-    QList<QKeySequence> shortcuts;
-    shortcuts << QKeySequence("Del") << QKeySequence("Backspace");
-    removeAct->setShortcuts(shortcuts);
+    removeAct->setShortcuts(QList<QKeySequence>() << QKeySequence("Del") << QKeySequence("Backspace"));
     removeAct->setEnabled(false);
     actions->insert("remove", removeAct);
     connect(removeAct, SIGNAL(triggered()), mediaView, SLOT(removeSelected()));
 
-    moveUpAct = new QAction(QtIconLoader::icon("go-up", QIcon(":/images/go-up.png")), tr("Move &Up"), this);
+    moveUpAct = new QAction(tr("Move &Up"), this);
     moveUpAct->setStatusTip(tr("Move up the selected videos in the playlist"));
     moveUpAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Up));
     moveUpAct->setEnabled(false);
     actions->insert("moveUp", moveUpAct);
     connect(moveUpAct, SIGNAL(triggered()), mediaView, SLOT(moveUpSelected()));
 
-    moveDownAct = new QAction(QtIconLoader::icon("go-down", QIcon(":/images/go-down.png")), tr("Move &Down"), this);
+    moveDownAct = new QAction(tr("Move &Down"), this);
     moveDownAct->setStatusTip(tr("Move down the selected videos in the playlist"));
     moveDownAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Down));
     moveDownAct->setEnabled(false);
     actions->insert("moveDown", moveDownAct);
     connect(moveDownAct, SIGNAL(triggered()), mediaView, SLOT(moveDownSelected()));
 
+    clearAct = new QAction(tr("&Clear recent keywords"), this);
+    clearAct->setMenuRole(QAction::ApplicationSpecificRole);
+    clearAct->setShortcuts(QList<QKeySequence>()
+                           << QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Delete)
+                           << QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Backspace));
+    clearAct->setStatusTip(tr("Clear the search history. Cannot be undone."));
+    clearAct->setEnabled(true);
+    actions->insert("clearRecentKeywords", clearAct);
+    connect(clearAct, SIGNAL(triggered()), SLOT(clearRecentKeywords()));
+
     quitAct = new QAction(tr("&Quit"), this);
     quitAct->setMenuRole(QAction::QuitRole);
-    quitAct->setShortcut(tr("Ctrl+Q"));
+    quitAct->setShortcuts(QList<QKeySequence>() << QKeySequence(tr("Ctrl+Q")) << QKeySequence(Qt::CTRL + Qt::Key_W));
     quitAct->setStatusTip(tr("Bye"));
     actions->insert("quit", quitAct);
-    connect(quitAct, SIGNAL(triggered()), this, SLOT(quit()));
+    connect(quitAct, SIGNAL(triggered()), this, SLOT(close()));
 
     siteAct = new QAction(tr("&Website"), this);
     siteAct->setShortcut(QKeySequence::HelpContents);
@@ -181,7 +204,7 @@ void MainWindow::createActions() {
     actions->insert("site", siteAct);
     connect(siteAct, SIGNAL(triggered()), this, SLOT(visitSite()));
 
-    donateAct = new QAction(tr("&Donate via PayPal"), this);
+    donateAct = new QAction(tr("Make a &donation"), this);
     donateAct->setStatusTip(tr("Please support the continued development of %1").arg(Constants::APP_NAME));
     actions->insert("donate", donateAct);
     connect(donateAct, SIGNAL(triggered()), this, SLOT(donate()));
@@ -192,12 +215,82 @@ void MainWindow::createActions() {
     actions->insert("about", aboutAct);
     connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
 
-    searchFocusAct = new QAction(tr("&Search"), this);
+    // Invisible actions
+
+    searchFocusAct = new QAction(this);
     searchFocusAct->setShortcut(QKeySequence::Find);
+    searchFocusAct->setStatusTip(tr("Search"));
     actions->insert("search", searchFocusAct);
     connect(searchFocusAct, SIGNAL(triggered()), this, SLOT(searchFocus()));
     addAction(searchFocusAct);
 
+    volumeUpAct = new QAction(this);
+    volumeUpAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_Plus) << QKeySequence(Qt::Key_VolumeUp));
+    actions->insert("volume-up", volumeUpAct);
+    connect(volumeUpAct, SIGNAL(triggered()), this, SLOT(volumeUp()));
+    addAction(volumeUpAct);
+
+    volumeDownAct = new QAction(this);
+    volumeDownAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_Minus) << QKeySequence(Qt::Key_VolumeDown));
+    actions->insert("volume-down", volumeDownAct);
+    connect(volumeDownAct, SIGNAL(triggered()), this, SLOT(volumeDown()));
+    addAction(volumeDownAct);
+
+    volumeMuteAct = new QAction(this);
+    volumeMuteAct->setIcon(QtIconLoader::icon("audio-volume-high"));
+    volumeMuteAct->setStatusTip(tr("Mute volume"));
+    volumeMuteAct->setShortcuts(QList<QKeySequence>()
+                                << QKeySequence(tr("Ctrl+M"))
+                                << QKeySequence(Qt::Key_VolumeMute));
+    actions->insert("volume-mute", volumeMuteAct);
+    connect(volumeMuteAct, SIGNAL(triggered()), SLOT(volumeMute()));
+    addAction(volumeMuteAct);
+
+    QAction *definitionAct = new QAction(this);
+    definitionAct->setIcon(QtIconLoader::icon("video-display"));
+    definitionAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_D));
+    /*
+    QMenu *definitionMenu = new QMenu(this);
+    foreach (QString definition, VideoDefinition::getDefinitionNames()) {
+        definitionMenu->addAction(definition);
+    }
+    definitionAct->setMenu(definitionMenu);
+    */
+    actions->insert("definition", definitionAct);
+    connect(definitionAct, SIGNAL(triggered()), SLOT(toggleDefinitionMode()));
+    addAction(definitionAct);
+
+    QAction *action;
+
+    /*
+    action = new QAction(tr("&Autoplay"), this);
+    action->setStatusTip(tr("Automatically start playing videos"));
+    action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_P));
+    action->setCheckable(true);
+    connect(action, SIGNAL(toggled(bool)), SLOT(setAutoplay(bool)));
+    actions->insert("autoplay", action);
+    */
+
+    action = new QAction(tr("&Downloads"), this);
+    action->setStatusTip(tr("Show details about video downloads"));
+    action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_J));
+    action->setCheckable(true);
+    action->setIcon(QtIconLoader::icon("go-down"));
+    action->setVisible(false);
+    connect(action, SIGNAL(toggled(bool)), SLOT(toggleDownloads(bool)));
+    actions->insert("downloads", action);
+
+    action = new QAction(tr("&Download"), this);
+    action->setStatusTip(tr("Download the current video"));
+    action->setShortcut(QKeySequence::Save);
+    action->setIcon(QtIconLoader::icon("go-down"));
+    action->setEnabled(false);
+#if QT_VERSION >= 0x040600
+    action->setPriority(QAction::LowPriority);
+#endif
+    connect(action, SIGNAL(triggered()), mediaView, SLOT(downloadVideo()));
+    actions->insert("download", action);
+
     // common action properties
     foreach (QAction *action, actions->values()) {
 
@@ -208,15 +301,18 @@ void MainWindow::createActions() {
         // never autorepeat.
         // unexperienced users tend to keep keys pressed for a "long" time
         action->setAutoRepeat(false);
-        action->setToolTip(action->statusTip());
 
-        // make the actions work when video is fullscreen
-        action->setShortcutContext(Qt::ApplicationShortcut);
+        // set to something more meaningful then the toolbar text
+        // HELP! how to remove tooltips altogether?!
+        if (!action->statusTip().isEmpty())
+            action->setToolTip(action->statusTip());
+
+        // show keyboard shortcuts in the status bar
+        if (!action->shortcut().isEmpty())
+            action->setStatusTip(action->statusTip() + " (" + action->shortcut().toString(QKeySequence::NativeText) + ")");
 
-#ifdef Q_WS_MAC
-        // OSX does not use icons in menus
+        // no icons in menus
         action->setIconVisibleInMenu(false);
-#endif
 
     }
 
@@ -228,10 +324,10 @@ void MainWindow::createMenus() {
 
     fileMenu = menuBar()->addMenu(tr("&Application"));
     // menus->insert("file", fileMenu);
-    /*
-    fileMenu->addAction(settingsAct);
+    fileMenu->addAction(clearAct);
+#ifndef APP_MAC
     fileMenu->addSeparator();
-    */
+#endif
     fileMenu->addAction(quitAct);
 
     playlistMenu = menuBar()->addMenu(tr("&Playlist"));
@@ -243,15 +339,22 @@ void MainWindow::createMenus() {
 
     viewMenu = menuBar()->addMenu(tr("&Video"));
     menus->insert("video", viewMenu);
-    // viewMenu->addAction(backAct);
     viewMenu->addAction(stopAct);
     viewMenu->addAction(pauseAct);
     viewMenu->addAction(skipAct);
     viewMenu->addSeparator();
+    viewMenu->addAction(The::globalActions()->value("download"));
+    viewMenu->addSeparator();
     viewMenu->addAction(webPageAct);
+    viewMenu->addAction(copyPageAct);
+    viewMenu->addAction(copyLinkAct);
     viewMenu->addSeparator();
     viewMenu->addAction(compactViewAct);
     viewMenu->addAction(fullscreenAct);
+#ifdef APP_MAC
+    extern void qt_mac_set_dock_menu(QMenu *);
+    qt_mac_set_dock_menu(viewMenu);
+#endif
 
     helpMenu = menuBar()->addMenu(tr("&Help"));
     helpMenu->addAction(siteAct);
@@ -261,48 +364,86 @@ void MainWindow::createMenus() {
 
 void MainWindow::createToolBars() {
 
-    setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
+    setUnifiedTitleAndToolBarOnMac(true);
 
     mainToolBar = new QToolBar(this);
+#if QT_VERSION < 0x040600 | defined(APP_MAC)
+    mainToolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
+#else
+    mainToolBar->setToolButtonStyle(Qt::ToolButtonFollowStyle);
+#endif
     mainToolBar->setFloatable(false);
     mainToolBar->setMovable(false);
 
-    QFont smallerFont;
-    smallerFont.setPointSize(smallerFont.pointSize()*.85);
-    mainToolBar->setFont(smallerFont);
+#ifdef APP_MAC
+    mainToolBar->setIconSize(QSize(32, 32));
+#endif
 
-    mainToolBar->setIconSize(QSize(32,32));
-    // mainToolBar->addAction(backAct);
     mainToolBar->addAction(stopAct);
     mainToolBar->addAction(pauseAct);
     mainToolBar->addAction(skipAct);
     mainToolBar->addAction(fullscreenAct);
+    mainToolBar->addAction(The::globalActions()->value("download"));
+
+    mainToolBar->addWidget(new Spacer());
+
+    QFont smallerFont = FontUtils::small();
+    currentTime = new QLabel(mainToolBar);
+    currentTime->setFont(smallerFont);
+    mainToolBar->addWidget(currentTime);
+
+    mainToolBar->addWidget(new Spacer());
 
     seekSlider = new Phonon::SeekSlider(this);
     seekSlider->setIconVisible(false);
-    Spacer *seekSliderSpacer = new Spacer(mainToolBar, seekSlider);
-    seekSliderSpacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
-    mainToolBar->addWidget(seekSliderSpacer);
+    seekSlider->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
+    mainToolBar->addWidget(seekSlider);
+
+    mainToolBar->addWidget(new Spacer());
+
+    totalTime = new QLabel(mainToolBar);
+    totalTime->setFont(smallerFont);
+    mainToolBar->addWidget(totalTime);
+
+    mainToolBar->addWidget(new Spacer());
+
+    mainToolBar->addAction(volumeMuteAct);
 
     volumeSlider = new Phonon::VolumeSlider(this);
+    volumeSlider->setMuteVisible(false);
+    // qDebug() << volumeSlider->children();
+    // status tip for the volume slider
+    QSlider* volumeQSlider = volumeSlider->findChild<QSlider*>();
+    if (volumeQSlider)
+        volumeQSlider->setStatusTip(tr("Press %1 to raise the volume, %2 to lower it").arg(
+                volumeUpAct->shortcut().toString(QKeySequence::NativeText), volumeDownAct->shortcut().toString(QKeySequence::NativeText)));
     // this makes the volume slider smaller
     volumeSlider->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
-    mainToolBar->addWidget(new Spacer(mainToolBar, volumeSlider));
+    mainToolBar->addWidget(volumeSlider);
+
+    mainToolBar->addWidget(new Spacer());
 
-    mainToolBar->addWidget(new Spacer(mainToolBar, toolbarSearch));
+    toolbarSearch->setStatusTip(searchFocusAct->statusTip());
+    mainToolBar->addWidget(toolbarSearch);
+
+    mainToolBar->addWidget(new Spacer());
 
     addToolBar(mainToolBar);
 }
 
 void MainWindow::createStatusBar() {
-    currentTime = new QLabel(this);
-    statusBar()->addPermanentWidget(currentTime);
-
-    totalTime = new QLabel(this);
-    statusBar()->addPermanentWidget(totalTime);
 
     // remove ugly borders on OSX
-    statusBar()->setStyleSheet("::item{border:0 solid}");
+    // also remove excessive spacing
+    statusBar()->setStyleSheet("::item{border:0 solid} QToolBar {padding:0;spacing:0;margin:0}");
+
+    QToolBar *toolBar = new QToolBar(this);
+    toolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
+    toolBar->setIconSize(QSize(16, 16));
+    toolBar->addAction(The::globalActions()->value("downloads"));
+    // toolBar->addAction(The::globalActions()->value("autoplay"));
+    toolBar->addAction(The::globalActions()->value("definition"));
+    statusBar()->addPermanentWidget(toolBar);
 
     statusBar()->show();
 }
@@ -310,14 +451,27 @@ void MainWindow::createStatusBar() {
 void MainWindow::readSettings() {
     QSettings settings;
     restoreGeometry(settings.value("geometry").toByteArray());
+#ifdef APP_MAC
+    if (!isMaximized())
+        move(x(), y() + mainToolBar->height() + 8);
+#endif
+    setDefinitionMode(settings.value("definition", VideoDefinition::getDefinitionNames().first()).toString());
+    audioOutput->setVolume(settings.value("volume", 1).toDouble());
+    audioOutput->setMuted(settings.value("volumeMute").toBool());
 }
 
 void MainWindow::writeSettings() {
-    // do not save geometry when in full screen
-    if (m_fullscreen)
-        return;
+
     QSettings settings;
-    settings.setValue("geometry", saveGeometry());
+
+    // do not save geometry when in full screen
+    if (!m_fullscreen) {
+        settings.setValue("geometry", saveGeometry());
+    }
+
+    settings.setValue("volume", audioOutput->volume());
+    settings.setValue("volumeMute", audioOutput->isMuted());
+    mediaView->saveSplitterState();
 }
 
 void MainWindow::goBack() {
@@ -334,13 +488,13 @@ void MainWindow::showWidget ( QWidget* widget ) {
 
     // call hide method on the current view
     View* oldView = dynamic_cast<View *> (views->currentWidget());
-    if (oldView != NULL) {
+    if (oldView) {
         oldView->disappear();
     }
 
     // call show method on the new view
     View* newView = dynamic_cast<View *> (widget);
-    if (newView != NULL) {
+    if (newView) {
         newView->appear();
         QMap<QString,QVariant> metadata = newView->metadata();
         QString windowTitle = metadata.value("title").toString();
@@ -348,36 +502,46 @@ void MainWindow::showWidget ( QWidget* widget ) {
             windowTitle += " - ";
         setWindowTitle(windowTitle + Constants::APP_NAME);
         statusBar()->showMessage((metadata.value("description").toString()));
-
     }
 
-    // backAct->setEnabled(history->size() > 1);
-    // settingsAct->setEnabled(widget != settingsView);
     stopAct->setEnabled(widget == mediaView);
     fullscreenAct->setEnabled(widget == mediaView);
     compactViewAct->setEnabled(widget == mediaView);
     webPageAct->setEnabled(widget == mediaView);
+    copyPageAct->setEnabled(widget == mediaView);
+    copyLinkAct->setEnabled(widget == mediaView);
     aboutAct->setEnabled(widget != aboutView);
-
-    // cool toolbar on the Mac
-    // setUnifiedTitleAndToolBarOnMac(widget == mediaView);
+    The::globalActions()->value("download")->setEnabled(widget == mediaView);
+    The::globalActions()->value("downloads")->setChecked(widget == downloadView);
 
     // toolbar only for the mediaView
-    mainToolBar->setVisible(widget == mediaView && !compactViewAct->isChecked());
+    /* mainToolBar->setVisible(
+            (widget == mediaView && !compactViewAct->isChecked())
+            || widget == downloadView
+            ); */
 
-    history->push(widget);
-    fadeInWidget(views->currentWidget(), widget);
+    setUpdatesEnabled(true);
+
+    QWidget *oldWidget = views->currentWidget();
     views->setCurrentWidget(widget);
 
-    setUpdatesEnabled(true);
+#ifdef APP_MAC
+    // crossfade only on OSX
+    // where we can be sure of video performance
+    fadeInWidget(oldWidget, widget);
+#endif
+
+    history->push(widget);
 }
 
 void MainWindow::fadeInWidget(QWidget *oldWidget, QWidget *newWidget) {
     if (faderWidget) faderWidget->close();
-    if (!oldWidget || !newWidget || oldWidget == mediaView || newWidget == mediaView) return;
-    QPixmap frozenView = QPixmap::grabWidget(oldWidget);
+    if (!oldWidget || !newWidget) {
+        // qDebug() << "no widgets";
+        return;
+    }
     faderWidget = new FaderWidget(newWidget);
-    faderWidget->start(frozenView);
+    faderWidget->start(QPixmap::grabWidget(oldWidget));
 }
 
 void MainWindow::about() {
@@ -406,16 +570,26 @@ void MainWindow::quit() {
 }
 
 void MainWindow::closeEvent(QCloseEvent *event) {
-    quit();
-    QWidget::closeEvent(event);
-}
+    if (DownloadManager::instance()->activeItems() > 0) {
+        QMessageBox msgBox;
+        msgBox.setIconPixmap(QPixmap(":/images/app.png").scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation));
+        msgBox.setText(tr("Do you want to exit %1 with a download in progress?").arg(Constants::APP_NAME));
+        msgBox.setInformativeText(tr("If you close %1 now, this download will be cancelled.").arg(Constants::APP_NAME));
+        msgBox.setModal(true);
+
+        msgBox.addButton(tr("Close and cancel download"), QMessageBox::RejectRole);
+        QPushButton *waitButton = msgBox.addButton(tr("Wait for download to finish"), QMessageBox::ActionRole);
+
+        msgBox.exec();
+
+        if (msgBox.clickedButton() == waitButton) {
+            event->ignore();
+            return;
+        }
 
-void MainWindow::showSettings() {
-    if (!settingsView) {
-        settingsView = new SettingsView(this);
-        views->addWidget(settingsView);
     }
-    showWidget(settingsView);
+    quit();
+    QWidget::closeEvent(event);
 }
 
 void MainWindow::showSearch() {
@@ -425,8 +599,6 @@ void MainWindow::showSearch() {
 }
 
 void MainWindow::showMedia(QString query) {
-    initPhonon();
-    mediaView->setMediaObject(mediaObject);
     SearchParams *searchParams = new SearchParams();
     searchParams->setKeywords(query);
     mediaView->search(searchParams);
@@ -439,7 +611,7 @@ void MainWindow::stateChanged(Phonon::State newState, Phonon::State /* oldState
 
     switch (newState) {
 
-         case Phonon::ErrorState:
+    case Phonon::ErrorState:
         if (mediaObject->errorType() == Phonon::FatalError) {
             statusBar()->showMessage(tr("Fatal error: %1").arg(mediaObject->errorString()));
         } else {
@@ -449,23 +621,26 @@ void MainWindow::stateChanged(Phonon::State newState, Phonon::State /* oldState
 
          case Phonon::PlayingState:
         pauseAct->setEnabled(true);
-        pauseAct->setIcon(QtIconLoader::icon("media-pause", QIcon(":/images/pause.png")));
+        pauseAct->setIcon(QtIconLoader::icon("media-playback-pause"));
         pauseAct->setText(tr("&Pause"));
-        pauseAct->setStatusTip(tr("Pause playback"));
+        pauseAct->setStatusTip(tr("Pause playback") + " (" +  pauseAct->shortcut().toString(QKeySequence::NativeText) + ")");
         skipAct->setEnabled(true);
+        // stopAct->setEnabled(true);
         break;
 
          case Phonon::StoppedState:
         pauseAct->setEnabled(false);
         skipAct->setEnabled(false);
+        // stopAct->setEnabled(false);
         break;
 
          case Phonon::PausedState:
         skipAct->setEnabled(true);
         pauseAct->setEnabled(true);
-        pauseAct->setIcon(QtIconLoader::icon("media-play", QIcon(":/images/play.png")));
+        pauseAct->setIcon(QtIconLoader::icon("media-playback-start"));
         pauseAct->setText(tr("&Play"));
-        pauseAct->setStatusTip(tr("Resume playback"));
+        pauseAct->setStatusTip(tr("Resume playback") + " (" +  pauseAct->shortcut().toString(QKeySequence::NativeText) + ")");
+        // stopAct->setEnabled(true);
         break;
 
          case Phonon::BufferingState:
@@ -474,6 +649,7 @@ void MainWindow::stateChanged(Phonon::State newState, Phonon::State /* oldState
         pauseAct->setEnabled(false);
         currentTime->clear();
         totalTime->clear();
+        // stopAct->setEnabled(true);
         break;
 
          default:
@@ -488,18 +664,71 @@ void MainWindow::stop() {
 
 void MainWindow::fullscreen() {
 
+    // No compact view action when in full screen
+    compactViewAct->setVisible(m_fullscreen);
+    compactViewAct->setChecked(false);
+
+    // Also no Youtube action since it opens a new window
+    webPageAct->setVisible(m_fullscreen);
+    copyPageAct->setVisible(m_fullscreen);
+    copyLinkAct->setVisible(m_fullscreen);
+
+    stopAct->setVisible(m_fullscreen);
+
+    // workaround: prevent focus on the search bar
+    // it steals the Space key needed for Play/Pause
+    toolbarSearch->setEnabled(m_fullscreen);
+
+    // Hide anything but the video
+    mediaView->setPlaylistVisible(m_fullscreen);
+    statusBar()->setVisible(m_fullscreen);
+
+#ifndef APP_MAC
+    menuBar()->setVisible(m_fullscreen);
+#endif
+
+#ifdef APP_MAC
+    // make the actions work when video is fullscreen (on the Mac)
+    QMap<QString, QAction*> *actions = The::globalActions();
+    foreach (QAction *action, actions->values()) {
+        if (m_fullscreen) {
+            action->setShortcutContext(Qt::WindowShortcut);
+        } else {
+            action->setShortcutContext(Qt::ApplicationShortcut);
+        }
+    }
+#endif
+
     if (m_fullscreen) {
-        fullscreenAct->setShortcut(QKeySequence(Qt::ALT + Qt::Key_Return));
+
+        // Exit full screen
+
+        // use setShortcuts instead of setShortcut
+        // the latter seems not to work
+        fullscreenAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::ALT + Qt::Key_Return));
         fullscreenAct->setText(tr("&Full Screen"));
-        stopAct->setShortcut(QKeySequence(Qt::Key_Escape));
+        stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
+
+#ifdef APP_MAC
+        setCentralWidget(views);
+        views->showNormal();
+        show();
+        mediaView->setFocus();
+#else
+        mainToolBar->show();
         if (m_maximized) showMaximized();
         else showNormal();
+#endif
+
+        // Make sure the window has focus
+        activateWindow();
+
     } else {
-        stopAct->setShortcut(QString(""));
-        QList<QKeySequence> shortcuts;
-        // for some reason it is important that ESC comes first
-        shortcuts << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::ALT + Qt::Key_Return);
-        fullscreenAct->setShortcuts(shortcuts);
+
+        // Enter full screen
+
+        stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_MediaStop));
+        fullscreenAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::ALT + Qt::Key_Return));
         fullscreenAct->setText(tr("Exit &Full Screen"));
         m_maximized = isMaximized();
 
@@ -507,17 +736,16 @@ void MainWindow::fullscreen() {
         // geometry won't be saved
         writeSettings();
 
+#ifdef APP_MAC
+        hide();
+        views->setParent(0);
+        QTimer::singleShot(0, views, SLOT(showFullScreen()));
+#else
+        mainToolBar->hide();
         showFullScreen();
-    }
-
-    // No compact view action when in full screen
-    compactViewAct->setVisible(m_fullscreen);
+#endif
 
-    // Hide anything but the video
-    mediaView->setPlaylistVisible(m_fullscreen);
-    mainToolBar->setVisible(m_fullscreen);
-    statusBar()->setVisible(m_fullscreen);
-    menuBar()->setVisible(m_fullscreen);
+    }
 
     m_fullscreen = !m_fullscreen;
 
@@ -525,24 +753,25 @@ void MainWindow::fullscreen() {
 
 void MainWindow::compactView(bool enable) {
 
-    // setUnifiedTitleAndToolBarOnMac(!enable);
     mediaView->setPlaylistVisible(!enable);
-    mainToolBar->setVisible(!enable);
     statusBar()->setVisible(!enable);
 
-    // ensure focus does not end up to the search box
-    // as it would steal the Space shortcut
-    toolbarSearch->setEnabled(!enable);
+#ifndef APP_MAC
+    menuBar()->setVisible(!enable);
+#endif
 
     if (enable) {
-        stopAct->setShortcut(QString(""));
-        QList<QKeySequence> shortcuts;
-        // for some reason it is important that ESC comes first
-        shortcuts << QKeySequence(Qt::CTRL + Qt::Key_Return) << QKeySequence(Qt::Key_Escape);
-        compactViewAct->setShortcuts(shortcuts);
+        stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_MediaStop));
+        compactViewAct->setShortcuts(
+                QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_Return)
+                << QKeySequence(Qt::Key_Escape));
+
+        // ensure focus does not end up to the search box
+        // as it would steal the Space shortcut
+        mediaView->setFocus();
     } else {
-        compactViewAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Return));
-        stopAct->setShortcut(QKeySequence(Qt::Key_Escape));
+        compactViewAct->setShortcuts(QList<QKeySequence>() <<  QKeySequence(Qt::CTRL + Qt::Key_Return));
+        stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
     }
 
 }
@@ -550,6 +779,7 @@ void MainWindow::compactView(bool enable) {
 void MainWindow::searchFocus() {
     QWidget *view = views->currentWidget();
     if (view == mediaView) {
+        toolbarSearch->selectAll();
         toolbarSearch->setFocus();
     }
 }
@@ -566,14 +796,24 @@ void MainWindow::initPhonon() {
     connect(mediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64)));
     seekSlider->setMediaObject(mediaObject);
     audioOutput = new Phonon::AudioOutput(Phonon::VideoCategory, this);
+    connect(audioOutput, SIGNAL(volumeChanged(qreal)), this, SLOT(volumeChanged(qreal)));
+    connect(audioOutput, SIGNAL(mutedChanged(bool)), this, SLOT(volumeMutedChanged(bool)));
     volumeSlider->setAudioOutput(audioOutput);
     Phonon::createPath(mediaObject, audioOutput);
 }
 
 void MainWindow::tick(qint64 time) {
-    QTime displayTime(0, (time / 60000) % 60, (time / 1000) % 60);
-    currentTime->setText(displayTime.toString("mm:ss"));
-    // qDebug() << "currentTime" << time << displayTime.toString("mm:ss");
+    if (time <= 0) {
+        currentTime->clear();
+        return;
+    }
+
+    currentTime->setText(formatTime(time));
+
+    // remaining time
+    const qint64 remainingTime = mediaObject->remainingTime();
+    currentTime->setStatusTip(tr("Remaining time: %1").arg(formatTime(remainingTime)));
+
 }
 
 void MainWindow::totalTimeChanged(qint64 time) {
@@ -581,8 +821,129 @@ void MainWindow::totalTimeChanged(qint64 time) {
         totalTime->clear();
         return;
     }
-    QTime displayTime(0, (time / 60000) % 60, (time / 1000) % 60);
-    totalTime->setText(displayTime.toString("/ mm:ss"));
-    // qDebug() << "totalTime" << time << displayTime.toString("mm:ss");
+    totalTime->setText(formatTime(time));
+}
+
+QString MainWindow::formatTime(qint64 time) {
+    QTime displayTime;
+    displayTime = displayTime.addMSecs(time);
+    QString timeString;
+    // 60 * 60 * 1000 = 3600000
+    if (time > 3600000)
+        timeString = displayTime.toString("h:mm:ss");
+    else
+        timeString = displayTime.toString("m:ss");
+    return timeString;
+}
+
+void MainWindow::volumeUp() {
+    qreal newVolume = volumeSlider->audioOutput()->volume() + .1;
+    if (newVolume > volumeSlider->maximumVolume())
+        newVolume = volumeSlider->maximumVolume();
+    volumeSlider->audioOutput()->setVolume(newVolume);
+}
+
+void MainWindow::volumeDown() {
+    qreal newVolume = volumeSlider->audioOutput()->volume() - .1;
+    if (newVolume < 0)
+        newVolume = 0;
+    volumeSlider->audioOutput()->setVolume(newVolume);
+}
+
+void MainWindow::volumeMute() {
+    volumeSlider->audioOutput()->setMuted(!volumeSlider->audioOutput()->isMuted());
+}
+
+void MainWindow::volumeChanged(qreal newVolume) {
+    // automatically unmute when volume changes
+    if (volumeSlider->audioOutput()->isMuted())
+        volumeSlider->audioOutput()->setMuted(false);
+    statusBar()->showMessage(tr("Volume at %1%").arg(newVolume*100));
+}
+
+void MainWindow::volumeMutedChanged(bool muted) {
+    if (muted) {
+        volumeMuteAct->setIcon(QtIconLoader::icon("audio-volume-muted"));
+        statusBar()->showMessage(tr("Volume is muted"));
+    } else {
+        volumeMuteAct->setIcon(QtIconLoader::icon("audio-volume-high"));
+        statusBar()->showMessage(tr("Volume is unmuted"));
+    }
+}
+
+void MainWindow::setDefinitionMode(QString definitionName) {
+    QAction *definitionAct = The::globalActions()->value("definition");
+    definitionAct->setText(definitionName);
+    definitionAct->setStatusTip(tr("Maximum video definition set to %1").arg(definitionAct->text())
+                                + " (" +  definitionAct->shortcut().toString(QKeySequence::NativeText) + ")");
+    statusBar()->showMessage(definitionAct->statusTip());
+    QSettings settings;
+    settings.setValue("definition", definitionName);
+}
+
+void MainWindow::toggleDefinitionMode() {
+    QSettings settings;
+    QString currentDefinition = settings.value("definition").toString();
+    QStringList definitionNames = VideoDefinition::getDefinitionNames();
+    int currentIndex = definitionNames.indexOf(currentDefinition);
+    int nextIndex = 0;
+    if (currentIndex != definitionNames.size() - 1) {
+        nextIndex = currentIndex + 1;
+    }
+    QString nextDefinition = definitionNames.at(nextIndex);
+    setDefinitionMode(nextDefinition);
+}
+
+void MainWindow::showFullscreenToolbar(bool show) {
+    if (!m_fullscreen) return;
+    mainToolBar->setVisible(show);
+}
+
+void MainWindow::showFullscreenPlaylist(bool show) {
+    if (!m_fullscreen) return;
+    mediaView->setPlaylistVisible(show);
+}
+
+void MainWindow::clearRecentKeywords() {
+    QSettings settings;
+    settings.remove("recentKeywords");
+    searchView->updateRecentKeywords();
+    statusBar()->showMessage(tr("Your privacy is now safe"));
 }
 
+/*
+ void MainWindow::setAutoplay(bool enabled) {
+     QSettings settings;
+     settings.setValue("autoplay", QVariant::fromValue(enabled));
+ }
+ */
+
+void MainWindow::updateDownloadMessage(QString message) {
+    The::globalActions()->value("downloads")->setText(message);
+}
+
+void MainWindow::downloadsFinished() {
+    The::globalActions()->value("downloads")->setText(tr("&Downloads"));
+    statusBar()->showMessage(tr("Downloads complete"));
+}
+
+void MainWindow::toggleDownloads(bool show) {
+
+    if (show) {
+        stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_MediaStop));
+        The::globalActions()->value("downloads")->setShortcuts(
+                QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_J)
+                << QKeySequence(Qt::Key_Escape));
+    } else {
+        The::globalActions()->value("downloads")->setShortcuts(
+                QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_J));
+        stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
+    }
+
+    if (!downloadView) {
+        downloadView = new DownloadView(this);
+        views->addWidget(downloadView);
+    }
+    if (show) showWidget(downloadView);
+    else goBack();
+}