1 #include "MainWindow.h"
4 #include "iconloader/qticonloader.h"
6 #include "videodefinition.h"
8 #include "globalshortcuts.h"
10 #include "gnomeglobalshortcutbackend.h"
13 #include "local/mac/mac_startup.h"
15 #include "downloadmanager.h"
16 #include "youtubesuggest.h"
18 MainWindow::MainWindow() :
26 history = new QStack<QWidget*>();
27 views = new QStackedWidget(this);
28 setCentralWidget(views);
31 searchView = new SearchView(this);
32 connect(searchView, SIGNAL(search(SearchParams*)), this, SLOT(showMedia(SearchParams*)));
33 views->addWidget(searchView);
35 mediaView = new MediaView(this);
36 views->addWidget(mediaView);
38 toolbarSearch = new SearchLineEdit(this);
39 toolbarSearch->setMinimumWidth(toolbarSearch->fontInfo().pixelSize()*15);
40 toolbarSearch->setSuggester(new YouTubeSuggest(this));
41 connect(toolbarSearch, SIGNAL(search(const QString&)), this, SLOT(startToolbarSearch(const QString&)));
50 // mediaView->setSlider(slider);
51 mediaView->setMediaObject(mediaObject);
53 // remove that useless menu/toolbar context menu
54 this->setContextMenuPolicy(Qt::NoContextMenu);
56 // mediaView init stuff thats needs actions
57 mediaView->initialize();
59 // event filter to block ugly toolbar tooltips
60 qApp->installEventFilter(this);
62 // restore window position
65 // show the initial view
66 showWidget(searchView);
69 GlobalShortcuts &shortcuts = GlobalShortcuts::instance();
71 if (GnomeGlobalShortcutBackend::IsGsdAvailable())
72 shortcuts.setBackend(new GnomeGlobalShortcutBackend(&shortcuts));
77 connect(&shortcuts, SIGNAL(PlayPause()), pauseAct, SLOT(trigger()));
78 connect(&shortcuts, SIGNAL(Stop()), this, SLOT(stop()));
79 connect(&shortcuts, SIGNAL(Next()), skipAct, SLOT(trigger()));
81 connect(DownloadManager::instance(), SIGNAL(statusMessageChanged(QString)),
82 SLOT(updateDownloadMessage(QString)));
83 connect(DownloadManager::instance(), SIGNAL(finished()),
84 SLOT(downloadsFinished()));
89 MainWindow::~MainWindow() {
93 bool MainWindow::eventFilter(QObject *obj, QEvent *event) {
94 if (event->type() == QEvent::MouseMove && this->m_fullscreen) {
95 QMouseEvent *mouseEvent = static_cast<QMouseEvent*> (event);
96 int x = mouseEvent->pos().x();
97 int y = mouseEvent->pos().y();
99 if (y < 0 && (obj == this->mainToolBar || !(y <= 10-this->mainToolBar->height() && y >= 0-this->mainToolBar->height() )))
100 this->mainToolBar->setVisible(false);
102 this->mediaView->setPlaylistVisible(false);
105 if (event->type() == QEvent::ToolTip) {
109 // standard event processing
110 return QObject::eventFilter(obj, event);
113 void MainWindow::createActions() {
115 QMap<QString, QAction*> *actions = The::globalActions();
117 stopAct = new QAction(QtIconLoader::icon("media-playback-stop"), tr("&Stop"), this);
118 stopAct->setStatusTip(tr("Stop playback and go back to the search view"));
119 stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
120 stopAct->setEnabled(false);
121 actions->insert("stop", stopAct);
122 connect(stopAct, SIGNAL(triggered()), this, SLOT(stop()));
124 skipAct = new QAction(QtIconLoader::icon("media-skip-forward"), tr("S&kip"), this);
125 skipAct->setStatusTip(tr("Skip to the next video"));
126 skipAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_Right) << QKeySequence(Qt::Key_MediaNext));
127 skipAct->setEnabled(false);
128 actions->insert("skip", skipAct);
129 connect(skipAct, SIGNAL(triggered()), mediaView, SLOT(skip()));
131 pauseAct = new QAction(QtIconLoader::icon("media-playback-pause"), tr("&Pause"), this);
132 pauseAct->setStatusTip(tr("Pause playback"));
133 pauseAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Space) << QKeySequence(Qt::Key_MediaPlay));
134 pauseAct->setEnabled(false);
135 actions->insert("pause", pauseAct);
136 connect(pauseAct, SIGNAL(triggered()), mediaView, SLOT(pause()));
138 fullscreenAct = new QAction(QtIconLoader::icon("view-fullscreen"), tr("&Full Screen"), this);
139 fullscreenAct->setStatusTip(tr("Go full screen"));
140 fullscreenAct->setShortcut(QKeySequence(Qt::ALT + Qt::Key_Return));
141 fullscreenAct->setShortcutContext(Qt::ApplicationShortcut);
142 #if QT_VERSION >= 0x040600
143 fullscreenAct->setPriority(QAction::LowPriority);
145 actions->insert("fullscreen", fullscreenAct);
146 connect(fullscreenAct, SIGNAL(triggered()), this, SLOT(fullscreen()));
148 compactViewAct = new QAction(tr("&Compact mode"), this);
149 compactViewAct->setStatusTip(tr("Hide the playlist and the toolbar"));
150 compactViewAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Return));
151 compactViewAct->setCheckable(true);
152 compactViewAct->setChecked(false);
153 compactViewAct->setEnabled(false);
154 actions->insert("compactView", compactViewAct);
155 connect(compactViewAct, SIGNAL(toggled(bool)), this, SLOT(compactView(bool)));
157 webPageAct = new QAction(tr("Open the &YouTube page"), this);
158 webPageAct->setStatusTip(tr("Go to the YouTube video page and pause playback"));
159 webPageAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Y));
160 webPageAct->setEnabled(false);
161 actions->insert("webpage", webPageAct);
162 connect(webPageAct, SIGNAL(triggered()), mediaView, SLOT(openWebPage()));
164 copyPageAct = new QAction(tr("Copy the YouTube &link"), this);
165 copyPageAct->setStatusTip(tr("Copy the current video YouTube link to the clipboard"));
166 copyPageAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_L));
167 copyPageAct->setEnabled(false);
168 actions->insert("pagelink", copyPageAct);
169 connect(copyPageAct, SIGNAL(triggered()), mediaView, SLOT(copyWebPage()));
171 copyLinkAct = new QAction(tr("Copy the video stream &URL"), this);
172 copyLinkAct->setStatusTip(tr("Copy the current video stream URL to the clipboard"));
173 copyLinkAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_U));
174 copyLinkAct->setEnabled(false);
175 actions->insert("videolink", copyLinkAct);
176 connect(copyLinkAct, SIGNAL(triggered()), mediaView, SLOT(copyVideoLink()));
178 removeAct = new QAction(tr("&Remove"), this);
179 removeAct->setStatusTip(tr("Remove the selected videos from the playlist"));
180 removeAct->setShortcuts(QList<QKeySequence>() << QKeySequence("Del") << QKeySequence("Backspace"));
181 removeAct->setEnabled(false);
182 actions->insert("remove", removeAct);
183 connect(removeAct, SIGNAL(triggered()), mediaView, SLOT(removeSelected()));
185 moveUpAct = new QAction(tr("Move &Up"), this);
186 moveUpAct->setStatusTip(tr("Move up the selected videos in the playlist"));
187 moveUpAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Up));
188 moveUpAct->setEnabled(false);
189 actions->insert("moveUp", moveUpAct);
190 connect(moveUpAct, SIGNAL(triggered()), mediaView, SLOT(moveUpSelected()));
192 moveDownAct = new QAction(tr("Move &Down"), this);
193 moveDownAct->setStatusTip(tr("Move down the selected videos in the playlist"));
194 moveDownAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Down));
195 moveDownAct->setEnabled(false);
196 actions->insert("moveDown", moveDownAct);
197 connect(moveDownAct, SIGNAL(triggered()), mediaView, SLOT(moveDownSelected()));
199 clearAct = new QAction(tr("&Clear recent searches"), this);
200 clearAct->setMenuRole(QAction::ApplicationSpecificRole);
201 clearAct->setShortcuts(QList<QKeySequence>()
202 << QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Delete)
203 << QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Backspace));
204 clearAct->setStatusTip(tr("Clear the search history. Cannot be undone."));
205 clearAct->setEnabled(true);
206 actions->insert("clearRecentKeywords", clearAct);
207 connect(clearAct, SIGNAL(triggered()), SLOT(clearRecentKeywords()));
209 quitAct = new QAction(tr("&Quit"), this);
210 quitAct->setMenuRole(QAction::QuitRole);
211 quitAct->setShortcuts(QList<QKeySequence>() << QKeySequence(tr("Ctrl+Q")) << QKeySequence(Qt::CTRL + Qt::Key_W));
212 quitAct->setStatusTip(tr("Bye"));
213 actions->insert("quit", quitAct);
214 connect(quitAct, SIGNAL(triggered()), this, SLOT(close()));
216 siteAct = new QAction(tr("&Website"), this);
217 siteAct->setShortcut(QKeySequence::HelpContents);
218 siteAct->setStatusTip(tr("%1 on the Web").arg(Constants::APP_NAME));
219 actions->insert("site", siteAct);
220 connect(siteAct, SIGNAL(triggered()), this, SLOT(visitSite()));
222 #if !defined(APP_MAC) && !defined(APP_WIN)
223 donateAct = new QAction(tr("Make a &donation"), this);
224 donateAct->setStatusTip(tr("Please support the continued development of %1").arg(Constants::APP_NAME));
225 actions->insert("donate", donateAct);
226 connect(donateAct, SIGNAL(triggered()), this, SLOT(donate()));
229 aboutAct = new QAction(tr("&About"), this);
230 aboutAct->setMenuRole(QAction::AboutRole);
231 aboutAct->setStatusTip(tr("Info about %1").arg(Constants::APP_NAME));
232 actions->insert("about", aboutAct);
233 connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
237 searchFocusAct = new QAction(this);
238 searchFocusAct->setShortcut(QKeySequence::Find);
239 searchFocusAct->setStatusTip(tr("Search"));
240 actions->insert("search", searchFocusAct);
241 connect(searchFocusAct, SIGNAL(triggered()), this, SLOT(searchFocus()));
242 addAction(searchFocusAct);
244 volumeUpAct = new QAction(this);
245 volumeUpAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_Plus) << QKeySequence(Qt::Key_VolumeUp));
246 actions->insert("volume-up", volumeUpAct);
247 connect(volumeUpAct, SIGNAL(triggered()), this, SLOT(volumeUp()));
248 addAction(volumeUpAct);
250 volumeDownAct = new QAction(this);
251 volumeDownAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_Minus) << QKeySequence(Qt::Key_VolumeDown));
252 actions->insert("volume-down", volumeDownAct);
253 connect(volumeDownAct, SIGNAL(triggered()), this, SLOT(volumeDown()));
254 addAction(volumeDownAct);
256 volumeMuteAct = new QAction(this);
257 volumeMuteAct->setIcon(QtIconLoader::icon("audio-volume-high"));
258 volumeMuteAct->setStatusTip(tr("Mute volume"));
259 volumeMuteAct->setShortcuts(QList<QKeySequence>()
260 << QKeySequence(tr("Ctrl+M"))
261 << QKeySequence(Qt::Key_VolumeMute));
262 actions->insert("volume-mute", volumeMuteAct);
263 connect(volumeMuteAct, SIGNAL(triggered()), SLOT(volumeMute()));
264 addAction(volumeMuteAct);
266 QAction *definitionAct = new QAction(this);
267 definitionAct->setIcon(QtIconLoader::icon("video-display"));
268 definitionAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_D));
270 QMenu *definitionMenu = new QMenu(this);
271 foreach (QString definition, VideoDefinition::getDefinitionNames()) {
272 definitionMenu->addAction(definition);
274 definitionAct->setMenu(definitionMenu);
276 actions->insert("definition", definitionAct);
277 connect(definitionAct, SIGNAL(triggered()), SLOT(toggleDefinitionMode()));
278 addAction(definitionAct);
283 action = new QAction(tr("&Autoplay"), this);
284 action->setStatusTip(tr("Automatically start playing videos"));
285 action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_P));
286 action->setCheckable(true);
287 connect(action, SIGNAL(toggled(bool)), SLOT(setAutoplay(bool)));
288 actions->insert("autoplay", action);
291 action = new QAction(tr("&Downloads"), this);
292 action->setStatusTip(tr("Show details about video downloads"));
293 action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_J));
294 action->setCheckable(true);
295 action->setIcon(QtIconLoader::icon("go-down"));
296 action->setVisible(false);
297 connect(action, SIGNAL(toggled(bool)), SLOT(toggleDownloads(bool)));
298 actions->insert("downloads", action);
300 action = new QAction(tr("&Download"), this);
301 action->setStatusTip(tr("Download the current video"));
302 #ifndef APP_NO_DOWNLOADS
303 action->setShortcut(QKeySequence::Save);
305 action->setIcon(QtIconLoader::icon("go-down"));
306 action->setEnabled(false);
307 #if QT_VERSION >= 0x040600
308 action->setPriority(QAction::LowPriority);
310 connect(action, SIGNAL(triggered()), mediaView, SLOT(downloadVideo()));
311 actions->insert("download", action);
313 // common action properties
314 foreach (QAction *action, actions->values()) {
316 // add actions to the MainWindow so that they work
317 // when the menu is hidden
321 // unexperienced users tend to keep keys pressed for a "long" time
322 action->setAutoRepeat(false);
324 // set to something more meaningful then the toolbar text
325 // HELP! how to remove tooltips altogether?!
326 if (!action->statusTip().isEmpty())
327 action->setToolTip(action->statusTip());
329 // show keyboard shortcuts in the status bar
330 if (!action->shortcut().isEmpty())
331 action->setStatusTip(action->statusTip() + " (" + action->shortcut().toString(QKeySequence::NativeText) + ")");
334 action->setIconVisibleInMenu(false);
340 void MainWindow::createMenus() {
342 QMap<QString, QMenu*> *menus = The::globalMenus();
344 fileMenu = menuBar()->addMenu(tr("&Application"));
345 // menus->insert("file", fileMenu);
346 fileMenu->addAction(clearAct);
348 fileMenu->addSeparator();
350 fileMenu->addAction(quitAct);
352 playlistMenu = menuBar()->addMenu(tr("&Playlist"));
353 menus->insert("playlist", playlistMenu);
354 playlistMenu->addAction(removeAct);
355 playlistMenu->addSeparator();
356 playlistMenu->addAction(moveUpAct);
357 playlistMenu->addAction(moveDownAct);
359 viewMenu = menuBar()->addMenu(tr("&Video"));
360 menus->insert("video", viewMenu);
361 viewMenu->addAction(stopAct);
362 viewMenu->addAction(pauseAct);
363 viewMenu->addAction(skipAct);
364 #ifndef APP_NO_DOWNLOADS
365 viewMenu->addSeparator();
366 viewMenu->addAction(The::globalActions()->value("download"));
368 viewMenu->addSeparator();
369 viewMenu->addAction(webPageAct);
370 viewMenu->addAction(copyPageAct);
371 #ifndef APP_NO_DOWNLOADS
372 viewMenu->addAction(copyLinkAct);
374 viewMenu->addSeparator();
375 viewMenu->addAction(compactViewAct);
376 viewMenu->addAction(fullscreenAct);
378 extern void qt_mac_set_dock_menu(QMenu *);
379 qt_mac_set_dock_menu(viewMenu);
382 helpMenu = menuBar()->addMenu(tr("&Help"));
383 helpMenu->addAction(siteAct);
384 #if !defined(APP_MAC) && !defined(APP_WIN)
385 helpMenu->addAction(donateAct);
387 helpMenu->addAction(aboutAct);
390 void MainWindow::createToolBars() {
392 setUnifiedTitleAndToolBarOnMac(true);
394 mainToolBar = new QToolBar(this);
395 #if QT_VERSION < 0x040600 | defined(APP_MAC)
396 mainToolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
397 #elif defined(APP_WIN)
398 mainToolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
399 mainToolBar->setStyleSheet(
401 "background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #fafcfd, stop:.5 #e6f0fa, stop:.51 #dde9f7, stop:1 #dde9f7);"
403 "border-bottom: 1px solid #a0afc3;"
406 mainToolBar->setToolButtonStyle(Qt::ToolButtonFollowStyle);
408 mainToolBar->setFloatable(false);
409 mainToolBar->setMovable(false);
411 #if defined(APP_MAC) | defined(APP_WIN)
412 mainToolBar->setIconSize(QSize(32, 32));
415 mainToolBar->addAction(stopAct);
416 mainToolBar->addAction(pauseAct);
417 mainToolBar->addAction(skipAct);
418 mainToolBar->addAction(fullscreenAct);
419 #ifndef APP_NO_DOWNLOADS
420 mainToolBar->addAction(The::globalActions()->value("download"));
423 mainToolBar->addWidget(new Spacer());
425 QFont smallerFont = FontUtils::small();
426 currentTime = new QLabel(mainToolBar);
427 currentTime->setFont(smallerFont);
428 mainToolBar->addWidget(currentTime);
430 mainToolBar->addWidget(new Spacer());
432 seekSlider = new Phonon::SeekSlider(this);
433 seekSlider->setIconVisible(false);
434 seekSlider->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
435 mainToolBar->addWidget(seekSlider);
438 mainToolBar->addWidget(new Spacer());
439 slider = new QSlider(this);
440 slider->setOrientation(Qt::Horizontal);
441 slider->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
442 mainToolBar->addWidget(slider);
445 mainToolBar->addWidget(new Spacer());
447 totalTime = new QLabel(mainToolBar);
448 totalTime->setFont(smallerFont);
449 mainToolBar->addWidget(totalTime);
451 mainToolBar->addWidget(new Spacer());
453 mainToolBar->addAction(volumeMuteAct);
455 volumeSlider = new Phonon::VolumeSlider(this);
456 volumeSlider->setMuteVisible(false);
457 // qDebug() << volumeSlider->children();
458 // status tip for the volume slider
459 QSlider* volumeQSlider = volumeSlider->findChild<QSlider*>();
461 volumeQSlider->setStatusTip(tr("Press %1 to raise the volume, %2 to lower it").arg(
462 volumeUpAct->shortcut().toString(QKeySequence::NativeText), volumeDownAct->shortcut().toString(QKeySequence::NativeText)));
463 // this makes the volume slider smaller
464 volumeSlider->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
465 mainToolBar->addWidget(volumeSlider);
467 mainToolBar->addWidget(new Spacer());
469 toolbarSearch->setStatusTip(searchFocusAct->statusTip());
470 mainToolBar->addWidget(toolbarSearch);
472 mainToolBar->addWidget(new Spacer());
474 addToolBar(mainToolBar);
477 void MainWindow::createStatusBar() {
479 // remove ugly borders on OSX
480 // also remove excessive spacing
481 statusBar()->setStyleSheet("::item{border:0 solid} QToolBar {padding:0;spacing:0;margin:0;border:0}");
483 QToolBar *toolBar = new QToolBar(this);
484 toolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
485 toolBar->setIconSize(QSize(16, 16));
486 toolBar->addAction(The::globalActions()->value("downloads"));
487 // toolBar->addAction(The::globalActions()->value("autoplay"));
488 toolBar->addAction(The::globalActions()->value("definition"));
489 statusBar()->addPermanentWidget(toolBar);
494 void MainWindow::readSettings() {
496 restoreGeometry(settings.value("geometry").toByteArray());
499 #ifdef QT_MAC_USE_COCOA
502 move(x(), y() + mainToolBar->height() + 8);
505 setDefinitionMode(settings.value("definition", VideoDefinition::getDefinitionNames().first()).toString());
506 audioOutput->setVolume(settings.value("volume", 1).toDouble());
507 audioOutput->setMuted(settings.value("volumeMute").toBool());
510 void MainWindow::writeSettings() {
514 // do not save geometry when in full screen
516 settings.setValue("geometry", saveGeometry());
519 settings.setValue("volume", audioOutput->volume());
520 settings.setValue("volumeMute", audioOutput->isMuted());
521 mediaView->saveSplitterState();
524 void MainWindow::goBack() {
525 if ( history->size() > 1 ) {
527 QWidget *widget = history->pop();
532 void MainWindow::showWidget ( QWidget* widget ) {
534 setUpdatesEnabled(false);
536 // call hide method on the current view
537 View* oldView = dynamic_cast<View *> (views->currentWidget());
539 oldView->disappear();
542 // call show method on the new view
543 View* newView = dynamic_cast<View *> (widget);
546 QMap<QString,QVariant> metadata = newView->metadata();
547 QString windowTitle = metadata.value("title").toString();
548 if (windowTitle.length())
549 windowTitle += " - ";
550 setWindowTitle(windowTitle + Constants::APP_NAME);
551 statusBar()->showMessage((metadata.value("description").toString()));
554 stopAct->setEnabled(widget == mediaView);
555 fullscreenAct->setEnabled(widget == mediaView);
556 compactViewAct->setEnabled(widget == mediaView);
557 webPageAct->setEnabled(widget == mediaView);
558 copyPageAct->setEnabled(widget == mediaView);
559 copyLinkAct->setEnabled(widget == mediaView);
560 aboutAct->setEnabled(widget != aboutView);
561 The::globalActions()->value("download")->setEnabled(widget == mediaView);
562 The::globalActions()->value("downloads")->setChecked(widget == downloadView);
564 // toolbar only for the mediaView
565 /* mainToolBar->setVisible(
566 (widget == mediaView && !compactViewAct->isChecked())
567 || widget == downloadView
570 setUpdatesEnabled(true);
572 QWidget *oldWidget = views->currentWidget();
573 views->setCurrentWidget(widget);
575 #if defined(APP_MAC) || defined(APP_WIN)
576 // crossfade only on OSX
577 // where we can be sure of video performance
578 fadeInWidget(oldWidget, widget);
581 history->push(widget);
584 void MainWindow::fadeInWidget(QWidget *oldWidget, QWidget *newWidget) {
585 if (faderWidget) faderWidget->close();
586 if (!oldWidget || !newWidget) {
587 // qDebug() << "no widgets";
590 faderWidget = new FaderWidget(newWidget);
591 faderWidget->start(QPixmap::grabWidget(oldWidget));
594 void MainWindow::about() {
596 aboutView = new AboutView(this);
597 views->addWidget(aboutView);
599 showWidget(aboutView);
602 void MainWindow::visitSite() {
603 QUrl url(Constants::WEBSITE);
604 statusBar()->showMessage(QString(tr("Opening %1").arg(url.toString())));
605 QDesktopServices::openUrl(url);
608 void MainWindow::donate() {
609 QUrl url(QString(Constants::WEBSITE) + "#donate");
610 statusBar()->showMessage(QString(tr("Opening %1").arg(url.toString())));
611 QDesktopServices::openUrl(url);
614 void MainWindow::quit() {
619 void MainWindow::closeEvent(QCloseEvent *event) {
620 if (DownloadManager::instance()->activeItems() > 0) {
622 msgBox.setIconPixmap(QPixmap(":/images/app.png").scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation));
623 msgBox.setText(tr("Do you want to exit %1 with a download in progress?").arg(Constants::APP_NAME));
624 msgBox.setInformativeText(tr("If you close %1 now, this download will be cancelled.").arg(Constants::APP_NAME));
625 msgBox.setModal(true);
627 msgBox.addButton(tr("Close and cancel download"), QMessageBox::RejectRole);
628 QPushButton *waitButton = msgBox.addButton(tr("Wait for download to finish"), QMessageBox::ActionRole);
632 if (msgBox.clickedButton() == waitButton) {
639 QWidget::closeEvent(event);
642 void MainWindow::showSearch() {
643 showWidget(searchView);
644 currentTime->clear();
648 void MainWindow::showMedia(SearchParams *searchParams) {
649 if (toolbarSearch->text().isEmpty() && !searchParams->keywords().isEmpty()) {
650 toolbarSearch->lineEdit()->setText(searchParams->keywords());
652 mediaView->search(searchParams);
653 showWidget(mediaView);
656 void MainWindow::stateChanged(Phonon::State newState, Phonon::State /* oldState */) {
658 // qDebug() << "Phonon state: " << newState;
662 case Phonon::ErrorState:
663 if (mediaObject->errorType() == Phonon::FatalError) {
664 // Do not display because we try to play incomplete video files and sometimes trigger this
665 // We retry automatically (in MediaView) so no need to show it
666 // statusBar()->showMessage(tr("Fatal error: %1").arg(mediaObject->errorString()));
668 statusBar()->showMessage(tr("Error: %1").arg(mediaObject->errorString()));
672 case Phonon::PlayingState:
673 pauseAct->setEnabled(true);
674 pauseAct->setIcon(QtIconLoader::icon("media-playback-pause"));
675 pauseAct->setText(tr("&Pause"));
676 pauseAct->setStatusTip(tr("Pause playback") + " (" + pauseAct->shortcut().toString(QKeySequence::NativeText) + ")");
677 skipAct->setEnabled(true);
678 // stopAct->setEnabled(true);
681 case Phonon::StoppedState:
682 pauseAct->setEnabled(false);
683 skipAct->setEnabled(false);
684 // stopAct->setEnabled(false);
687 case Phonon::PausedState:
688 skipAct->setEnabled(true);
689 pauseAct->setEnabled(true);
690 pauseAct->setIcon(QtIconLoader::icon("media-playback-start"));
691 pauseAct->setText(tr("&Play"));
692 pauseAct->setStatusTip(tr("Resume playback") + " (" + pauseAct->shortcut().toString(QKeySequence::NativeText) + ")");
693 // stopAct->setEnabled(true);
696 case Phonon::BufferingState:
697 case Phonon::LoadingState:
698 skipAct->setEnabled(true);
699 pauseAct->setEnabled(false);
700 currentTime->clear();
702 // stopAct->setEnabled(true);
710 void MainWindow::stop() {
715 void MainWindow::fullscreen() {
717 // No compact view action when in full screen
718 compactViewAct->setVisible(m_fullscreen);
719 compactViewAct->setChecked(false);
721 // Also no Youtube action since it opens a new window
722 webPageAct->setVisible(m_fullscreen);
723 copyPageAct->setVisible(m_fullscreen);
724 copyLinkAct->setVisible(m_fullscreen);
726 stopAct->setVisible(m_fullscreen);
728 // workaround: prevent focus on the search bar
729 // it steals the Space key needed for Play/Pause
730 toolbarSearch->setVisible(m_fullscreen);
731 toolbarSearch->setEnabled(m_fullscreen);
733 // Hide anything but the video
734 mediaView->setPlaylistVisible(m_fullscreen);
735 statusBar()->setVisible(m_fullscreen);
738 menuBar()->setVisible(m_fullscreen);
742 // make the actions work when video is fullscreen (on the Mac)
743 QMap<QString, QAction*> *actions = The::globalActions();
744 foreach (QAction *action, actions->values()) {
746 action->setShortcutContext(Qt::WindowShortcut);
748 action->setShortcutContext(Qt::ApplicationShortcut);
757 // use setShortcuts instead of setShortcut
758 // the latter seems not to work
759 fullscreenAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::ALT + Qt::Key_Return));
760 fullscreenAct->setText(tr("&Full Screen"));
761 stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
764 setCentralWidget(views);
767 mediaView->setFocus();
770 if (m_maximized) showMaximized();
774 // Make sure the window has focus
781 stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_MediaStop));
782 fullscreenAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::ALT + Qt::Key_Return));
783 fullscreenAct->setText(tr("Exit &Full Screen"));
784 m_maximized = isMaximized();
786 // save geometry now, if the user quits when in full screen
787 // geometry won't be saved
793 QTimer::singleShot(0, views, SLOT(showFullScreen()));
801 m_fullscreen = !m_fullscreen;
805 void MainWindow::compactView(bool enable) {
807 mediaView->setPlaylistVisible(!enable);
808 statusBar()->setVisible(!enable);
811 menuBar()->setVisible(!enable);
815 stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_MediaStop));
816 compactViewAct->setShortcuts(
817 QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_Return)
818 << QKeySequence(Qt::Key_Escape));
820 // ensure focus does not end up to the search box
821 // as it would steal the Space shortcut
822 mediaView->setFocus();
824 compactViewAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_Return));
825 stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
830 void MainWindow::searchFocus() {
831 QWidget *view = views->currentWidget();
832 if (view == mediaView) {
833 toolbarSearch->selectAll();
834 toolbarSearch->setFocus();
838 void MainWindow::initPhonon() {
839 // Phonon initialization
840 if (mediaObject) delete mediaObject;
841 if (audioOutput) delete audioOutput;
842 mediaObject = new Phonon::MediaObject(this);
843 mediaObject->setTickInterval(100);
844 connect(mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
845 this, SLOT(stateChanged(Phonon::State, Phonon::State)));
846 connect(mediaObject, SIGNAL(tick(qint64)), this, SLOT(tick(qint64)));
847 connect(mediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64)));
848 seekSlider->setMediaObject(mediaObject);
849 audioOutput = new Phonon::AudioOutput(Phonon::VideoCategory, this);
850 connect(audioOutput, SIGNAL(volumeChanged(qreal)), this, SLOT(volumeChanged(qreal)));
851 connect(audioOutput, SIGNAL(mutedChanged(bool)), this, SLOT(volumeMutedChanged(bool)));
852 volumeSlider->setAudioOutput(audioOutput);
853 Phonon::createPath(mediaObject, audioOutput);
856 void MainWindow::tick(qint64 time) {
858 currentTime->clear();
862 currentTime->setText(formatTime(time));
865 const qint64 remainingTime = mediaObject->remainingTime();
866 currentTime->setStatusTip(tr("Remaining time: %1").arg(formatTime(remainingTime)));
869 slider->blockSignals(true);
870 slider->setValue(time/1000);
871 slider->blockSignals(false);
875 void MainWindow::totalTimeChanged(qint64 time) {
880 totalTime->setText(formatTime(time));
883 slider->blockSignals(true);
884 slider->setMaximum(time/1000);
885 slider->blockSignals(false);
890 QString MainWindow::formatTime(qint64 time) {
892 displayTime = displayTime.addMSecs(time);
894 // 60 * 60 * 1000 = 3600000
896 timeString = displayTime.toString("h:mm:ss");
898 timeString = displayTime.toString("m:ss");
902 void MainWindow::volumeUp() {
903 qreal newVolume = volumeSlider->audioOutput()->volume() + .1;
904 if (newVolume > volumeSlider->maximumVolume())
905 newVolume = volumeSlider->maximumVolume();
906 volumeSlider->audioOutput()->setVolume(newVolume);
909 void MainWindow::volumeDown() {
910 qreal newVolume = volumeSlider->audioOutput()->volume() - .1;
913 volumeSlider->audioOutput()->setVolume(newVolume);
916 void MainWindow::volumeMute() {
917 volumeSlider->audioOutput()->setMuted(!volumeSlider->audioOutput()->isMuted());
920 void MainWindow::volumeChanged(qreal newVolume) {
921 // automatically unmute when volume changes
922 if (volumeSlider->audioOutput()->isMuted())
923 volumeSlider->audioOutput()->setMuted(false);
924 statusBar()->showMessage(tr("Volume at %1%").arg((int)(newVolume*100)));
927 void MainWindow::volumeMutedChanged(bool muted) {
929 volumeMuteAct->setIcon(QtIconLoader::icon("audio-volume-muted"));
930 statusBar()->showMessage(tr("Volume is muted"));
932 volumeMuteAct->setIcon(QtIconLoader::icon("audio-volume-high"));
933 statusBar()->showMessage(tr("Volume is unmuted"));
937 void MainWindow::setDefinitionMode(QString definitionName) {
938 QAction *definitionAct = The::globalActions()->value("definition");
939 definitionAct->setText(definitionName);
940 definitionAct->setStatusTip(tr("Maximum video definition set to %1").arg(definitionAct->text())
941 + " (" + definitionAct->shortcut().toString(QKeySequence::NativeText) + ")");
942 statusBar()->showMessage(definitionAct->statusTip());
944 settings.setValue("definition", definitionName);
947 void MainWindow::toggleDefinitionMode() {
949 QString currentDefinition = settings.value("definition").toString();
950 QStringList definitionNames = VideoDefinition::getDefinitionNames();
951 int currentIndex = definitionNames.indexOf(currentDefinition);
953 if (currentIndex != definitionNames.size() - 1) {
954 nextIndex = currentIndex + 1;
956 QString nextDefinition = definitionNames.at(nextIndex);
957 setDefinitionMode(nextDefinition);
960 void MainWindow::showFullscreenToolbar(bool show) {
961 if (!m_fullscreen) return;
962 mainToolBar->setVisible(show);
963 toolbarSearch->setVisible(show);
964 toolbarSearch->setEnabled(show);
967 void MainWindow::showFullscreenPlaylist(bool show) {
968 if (!m_fullscreen) return;
969 mediaView->setPlaylistVisible(show);
972 void MainWindow::clearRecentKeywords() {
974 settings.remove("recentKeywords");
975 settings.remove("recentChannels");
976 searchView->updateRecentKeywords();
977 searchView->updateRecentChannels();
978 statusBar()->showMessage(tr("Your privacy is now safe"));
982 void MainWindow::setAutoplay(bool enabled) {
984 settings.setValue("autoplay", QVariant::fromValue(enabled));
988 void MainWindow::updateDownloadMessage(QString message) {
989 The::globalActions()->value("downloads")->setText(message);
992 void MainWindow::downloadsFinished() {
993 The::globalActions()->value("downloads")->setText(tr("&Downloads"));
994 statusBar()->showMessage(tr("Downloads complete"));
997 void MainWindow::toggleDownloads(bool show) {
1000 stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_MediaStop));
1001 The::globalActions()->value("downloads")->setShortcuts(
1002 QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_J)
1003 << QKeySequence(Qt::Key_Escape));
1005 The::globalActions()->value("downloads")->setShortcuts(
1006 QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_J));
1007 stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
1010 if (!downloadView) {
1011 downloadView = new DownloadView(this);
1012 views->addWidget(downloadView);
1014 if (show) showWidget(downloadView);
1018 void MainWindow::startToolbarSearch(QString query) {
1020 query = query.trimmed();
1022 // check for empty query
1023 if (query.length() == 0) {
1027 SearchParams *searchParams = new SearchParams();
1028 searchParams->setKeywords(query);
1031 showMedia(searchParams);
1034 void MainWindow::dragEnterEvent(QDragEnterEvent *event) {
1035 if (event->mimeData()->hasFormat("text/uri-list")) {
1036 QList<QUrl> urls = event->mimeData()->urls();
1039 QUrl url = urls.first();
1040 QString videoId = YouTubeSearch::videoIdFromUrl(url.toString());
1041 if (!videoId.isNull())
1042 event->acceptProposedAction();
1046 void MainWindow::dropEvent(QDropEvent *event) {
1047 QList<QUrl> urls = event->mimeData()->urls();
1050 QUrl url = urls.first();
1051 QString videoId = YouTubeSearch::videoIdFromUrl(url.toString());
1052 if (!videoId.isNull()) {
1053 setWindowTitle(url.toString());
1054 SearchParams *searchParams = new SearchParams();
1055 searchParams->setKeywords(videoId);
1056 showMedia(searchParams);