X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2FMainWindow.cpp;h=c87c398be0d84b2e8d7c7be7362441f510d65d32;hb=e3f740d737612768e8abe395afadb131db190964;hp=3774bdc48e243f09044977313699bfcf341a668d;hpb=043f8407d9fb8c57b7544588d025a022d95c51ad;p=minitube diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 3774bdc..c87c398 100755 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -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(); 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 *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(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(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(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 shortcuts; - shortcuts << QKeySequence("Del") << QKeySequence("Backspace"); - removeAct->setShortcuts(shortcuts); + removeAct->setShortcuts(QList() << 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(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(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,26 +215,104 @@ 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(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(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(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(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()) { + + // add actions to the MainWindow so that they work + // when the menu is hidden + addAction(action); + // 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 } @@ -223,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")); @@ -238,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); @@ -256,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(); + 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(); } @@ -305,11 +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() { + 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() { @@ -322,15 +484,17 @@ void MainWindow::goBack() { void MainWindow::showWidget ( QWidget* widget ) { + setUpdatesEnabled(false); + // call hide method on the current view View* oldView = dynamic_cast (views->currentWidget()); - if (oldView != NULL) { + if (oldView) { oldView->disappear(); } // call show method on the new view View* newView = dynamic_cast (widget); - if (newView != NULL) { + if (newView) { newView->appear(); QMap metadata = newView->metadata(); QString windowTitle = metadata.value("title").toString(); @@ -338,35 +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); +#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() { @@ -395,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() { @@ -414,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); @@ -428,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 { @@ -438,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: @@ -463,6 +649,7 @@ void MainWindow::stateChanged(Phonon::State newState, Phonon::State /* oldState pauseAct->setEnabled(false); currentTime->clear(); totalTime->clear(); + // stopAct->setEnabled(true); break; default: @@ -477,21 +664,88 @@ 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 *actions = The::globalActions(); + foreach (QAction *action, actions->values()) { + if (m_fullscreen) { + action->setShortcutContext(Qt::WindowShortcut); + } else { + action->setShortcutContext(Qt::ApplicationShortcut); + } + } +#endif + if (m_fullscreen) { - mediaView->exitFullscreen(); - 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(Qt::ALT + Qt::Key_Return)); fullscreenAct->setText(tr("&Full Screen")); - stopAct->setShortcut(QKeySequence(Qt::Key_Escape)); + stopAct->setShortcuts(QList() << 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 { - mediaView->fullscreen(); - stopAct->setShortcut(QString("")); - QList shortcuts; - // for some reason it is importante 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(Qt::Key_MediaStop)); + fullscreenAct->setShortcuts(QList() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::ALT + Qt::Key_Return)); fullscreenAct->setText(tr("Exit &Full Screen")); + m_maximized = isMaximized(); + + // save geometry now, if the user quits when in full screen + // geometry won't be saved + writeSettings(); + +#ifdef APP_MAC + hide(); + views->setParent(0); + QTimer::singleShot(0, views, SLOT(showFullScreen())); +#else + mainToolBar->hide(); + showFullScreen(); +#endif + } - compactViewAct->setVisible(m_fullscreen); m_fullscreen = !m_fullscreen; @@ -499,20 +753,25 @@ void MainWindow::fullscreen() { void MainWindow::compactView(bool enable) { - // setUnifiedTitleAndToolBarOnMac(!enable); mediaView->setPlaylistVisible(!enable); - mainToolBar->setVisible(!enable); statusBar()->setVisible(!enable); +#ifndef APP_MAC + menuBar()->setVisible(!enable); +#endif + if (enable) { - stopAct->setShortcut(QString("")); - QList 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(Qt::Key_MediaStop)); + compactViewAct->setShortcuts( + QList() << 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(Qt::CTRL + Qt::Key_Return)); + stopAct->setShortcuts(QList() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop)); } } @@ -520,6 +779,7 @@ void MainWindow::compactView(bool enable) { void MainWindow::searchFocus() { QWidget *view = views->currentWidget(); if (view == mediaView) { + toolbarSearch->selectAll(); toolbarSearch->setFocus(); } } @@ -536,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) { @@ -551,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(Qt::Key_MediaStop)); + The::globalActions()->value("downloads")->setShortcuts( + QList() << QKeySequence(Qt::CTRL + Qt::Key_J) + << QKeySequence(Qt::Key_Escape)); + } else { + The::globalActions()->value("downloads")->setShortcuts( + QList() << QKeySequence(Qt::CTRL + Qt::Key_J)); + stopAct->setShortcuts(QList() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop)); + } + + if (!downloadView) { + downloadView = new DownloadView(this); + views->addWidget(downloadView); + } + if (show) showWidget(downloadView); + else goBack(); +}