1 #include "MainWindow.h"
4 #include "iconloader/qticonloader.h"
7 MainWindow::MainWindow() {
14 history = new QStack<QWidget*>();
15 views = new QStackedWidget(this);
18 searchView = new SearchView(this);
19 connect(searchView, SIGNAL(search(QString)), this, SLOT(showMedia(QString)));
20 views->addWidget(searchView);
21 mediaView = new MediaView(this);
22 views->addWidget(mediaView);
24 // lazily initialized views
28 toolbarSearch = new SearchLineEdit(this);
29 toolbarSearch->setFont(qApp->font());
30 connect(toolbarSearch, SIGNAL(search(const QString&)), searchView, SLOT(watch(const QString&)));
38 // remove that useless menu/toolbar context menu
39 this->setContextMenuPolicy(Qt::NoContextMenu);
41 // mediaView init stuff thats needs actions
42 mediaView->initialize();
44 // restore window position
47 // show the initial view
48 showWidget(searchView);
50 setCentralWidget(views);
54 MainWindow::~MainWindow() {
58 void MainWindow::createActions() {
60 QMap<QString, QAction*> *actions = The::globalActions();
63 settingsAct = new QAction(tr("&Preferences..."), this);
64 settingsAct->setStatusTip(tr(QString("Configure ").append(Constants::APP_NAME).toUtf8()));
66 settingsAct->setMenuRole(QAction::PreferencesRole);
67 actions->insert("settings", settingsAct);
68 connect(settingsAct, SIGNAL(triggered()), this, SLOT(showSettings()));
71 backAct = new QAction(QIcon(":/images/go-previous.png"), tr("&Back"), this);
72 backAct->setEnabled(false);
73 backAct->setShortcut(QKeySequence(Qt::ALT + Qt::Key_Left));
74 backAct->setStatusTip(tr("Go to the previous view"));
75 actions->insert("back", backAct);
76 connect(backAct, SIGNAL(triggered()), this, SLOT(goBack()));
78 stopAct = new QAction(QtIconLoader::icon("media-stop", QIcon(":/images/stop.png")), tr("&Stop"), this);
79 stopAct->setStatusTip(tr("Stop playback and go back to the search view"));
80 stopAct->setShortcut(QKeySequence(Qt::Key_Escape));
81 actions->insert("stop", stopAct);
82 connect(stopAct, SIGNAL(triggered()), this, SLOT(stop()));
84 skipAct = new QAction(QtIconLoader::icon("media-skip-forward", QIcon(":/images/skip.png")), tr("S&kip"), this);
85 skipAct->setStatusTip(tr("Skip to the next video"));
86 skipAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Right));
87 skipAct->setEnabled(false);
88 actions->insert("skip", skipAct);
89 connect(skipAct, SIGNAL(triggered()), mediaView, SLOT(skip()));
91 pauseAct = new QAction(QtIconLoader::icon("media-pause", QIcon(":/images/pause.png")), tr("&Pause"), this);
92 pauseAct->setStatusTip(tr("Pause playback"));
93 pauseAct->setShortcut(QKeySequence(Qt::Key_Space));
94 pauseAct->setEnabled(false);
95 actions->insert("pause", pauseAct);
96 connect(pauseAct, SIGNAL(triggered()), mediaView, SLOT(pause()));
98 fullscreenAct = new QAction(QtIconLoader::icon("view-fullscreen", QIcon(":/images/view-fullscreen.png")), tr("&Full Screen"), this);
99 fullscreenAct->setStatusTip(tr("Go full screen"));
100 fullscreenAct->setShortcut(QKeySequence(Qt::ALT + Qt::Key_Return));
101 fullscreenAct->setShortcutContext(Qt::ApplicationShortcut);
102 actions->insert("fullscreen", fullscreenAct);
103 connect(fullscreenAct, SIGNAL(triggered()), this, SLOT(fullscreen()));
105 compactViewAct = new QAction(tr("&Compact mode"), this);
106 compactViewAct->setStatusTip(tr("Hide the playlist and the toolbar"));
107 compactViewAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Return));
108 compactViewAct->setCheckable(true);
109 compactViewAct->setChecked(false);
110 compactViewAct->setEnabled(false);
111 actions->insert("compactView", compactViewAct);
112 connect(compactViewAct, SIGNAL(toggled(bool)), this, SLOT(compactView(bool)));
115 // icon should be document-save but it is ugly
116 downloadAct = new QAction(QtIconLoader::icon("go-down", QIcon(":/images/go-down.png")), tr("&Download"), this);
117 downloadAct->setStatusTip(tr("Download this video"));
118 downloadAct->setShortcut(tr("Ctrl+S"));
119 actions.insert("download", downloadAct);
120 connect(downloadAct, SIGNAL(triggered()), this, SLOT(download()));
123 webPageAct = new QAction(QtIconLoader::icon("internet-web-browser", QIcon(":/images/internet-web-browser.png")), tr("&YouTube"), this);
124 webPageAct->setStatusTip(tr("Open the YouTube video page"));
125 webPageAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Y));
126 webPageAct->setEnabled(false);
127 actions->insert("webpage", webPageAct);
128 connect(webPageAct, SIGNAL(triggered()), mediaView, SLOT(openWebPage()));
130 removeAct = new QAction(tr("&Remove"), this);
131 removeAct->setStatusTip(tr("Remove the selected videos from the playlist"));
132 QList<QKeySequence> shortcuts;
133 shortcuts << QKeySequence("Del") << QKeySequence("Backspace");
134 removeAct->setShortcuts(shortcuts);
135 removeAct->setEnabled(false);
136 actions->insert("remove", removeAct);
137 connect(removeAct, SIGNAL(triggered()), mediaView, SLOT(removeSelected()));
139 moveUpAct = new QAction(QtIconLoader::icon("go-up", QIcon(":/images/go-up.png")), tr("Move &Up"), this);
140 moveUpAct->setStatusTip(tr("Move up the selected videos in the playlist"));
141 moveUpAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Up));
142 moveUpAct->setEnabled(false);
143 actions->insert("moveUp", moveUpAct);
144 connect(moveUpAct, SIGNAL(triggered()), mediaView, SLOT(moveUpSelected()));
146 moveDownAct = new QAction(QtIconLoader::icon("go-down", QIcon(":/images/go-down.png")), tr("Move &Down"), this);
147 moveDownAct->setStatusTip(tr("Move down the selected videos in the playlist"));
148 moveDownAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Down));
149 moveDownAct->setEnabled(false);
150 actions->insert("moveDown", moveDownAct);
151 connect(moveDownAct, SIGNAL(triggered()), mediaView, SLOT(moveDownSelected()));
153 quitAct = new QAction(tr("&Quit"), this);
154 quitAct->setMenuRole(QAction::QuitRole);
155 quitAct->setShortcut(tr("Ctrl+Q"));
156 quitAct->setStatusTip(tr("Bye"));
157 actions->insert("quit", quitAct);
158 connect(quitAct, SIGNAL(triggered()), this, SLOT(quit()));
160 siteAct = new QAction(tr("&Website"), this);
161 siteAct->setShortcut(QKeySequence::HelpContents);
162 siteAct->setStatusTip(tr("%1 on the Web").arg(Constants::APP_NAME));
163 actions->insert("site", siteAct);
164 connect(siteAct, SIGNAL(triggered()), this, SLOT(visitSite()));
166 donateAct = new QAction(tr("&Donate via PayPal"), this);
167 donateAct->setStatusTip(tr("Please support the continued development of %1").arg(Constants::APP_NAME));
168 actions->insert("donate", donateAct);
169 connect(donateAct, SIGNAL(triggered()), this, SLOT(donate()));
171 aboutAct = new QAction(tr("&About"), this);
172 aboutAct->setMenuRole(QAction::AboutRole);
173 aboutAct->setStatusTip(tr("Info about %1").arg(Constants::APP_NAME));
174 actions->insert("about", aboutAct);
175 connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
177 searchFocusAct = new QAction(tr("&Search"), this);
178 searchFocusAct->setShortcut(QKeySequence::Find);
179 actions->insert("search", searchFocusAct);
180 connect(searchFocusAct, SIGNAL(triggered()), this, SLOT(searchFocus()));
181 addAction(searchFocusAct);
183 // common action properties
184 foreach (QAction *action, actions->values()) {
186 // add actions to the MainWindow so that they work
187 // when the menu is hidden
191 // unexperienced users tend to keep keys pressed for a "long" time
192 action->setAutoRepeat(false);
193 action->setToolTip(action->statusTip());
195 // make the actions work when video is fullscreen
196 action->setShortcutContext(Qt::ApplicationShortcut);
199 // OSX does not use icons in menus
200 action->setIconVisibleInMenu(false);
207 void MainWindow::createMenus() {
209 QMap<QString, QMenu*> *menus = The::globalMenus();
211 fileMenu = menuBar()->addMenu(tr("&Application"));
212 // menus->insert("file", fileMenu);
214 fileMenu->addAction(settingsAct);
215 fileMenu->addSeparator();
217 fileMenu->addAction(quitAct);
219 playlistMenu = menuBar()->addMenu(tr("&Playlist"));
220 menus->insert("playlist", playlistMenu);
221 playlistMenu->addAction(removeAct);
222 playlistMenu->addSeparator();
223 playlistMenu->addAction(moveUpAct);
224 playlistMenu->addAction(moveDownAct);
226 viewMenu = menuBar()->addMenu(tr("&Video"));
227 menus->insert("video", viewMenu);
228 // viewMenu->addAction(backAct);
229 viewMenu->addAction(stopAct);
230 viewMenu->addAction(pauseAct);
231 viewMenu->addAction(skipAct);
232 viewMenu->addSeparator();
233 viewMenu->addAction(webPageAct);
234 viewMenu->addSeparator();
235 viewMenu->addAction(compactViewAct);
236 viewMenu->addAction(fullscreenAct);
238 helpMenu = menuBar()->addMenu(tr("&Help"));
239 helpMenu->addAction(siteAct);
240 helpMenu->addAction(donateAct);
241 helpMenu->addAction(aboutAct);
244 void MainWindow::createToolBars() {
246 setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
248 mainToolBar = new QToolBar(this);
249 mainToolBar->setFloatable(false);
250 mainToolBar->setMovable(false);
253 smallerFont.setPointSize(smallerFont.pointSize()*.85);
254 mainToolBar->setFont(smallerFont);
256 mainToolBar->setIconSize(QSize(32,32));
257 // mainToolBar->addAction(backAct);
258 mainToolBar->addAction(stopAct);
259 mainToolBar->addAction(pauseAct);
260 mainToolBar->addAction(skipAct);
261 mainToolBar->addAction(fullscreenAct);
263 seekSlider = new Phonon::SeekSlider(this);
264 seekSlider->setIconVisible(false);
265 Spacer *seekSliderSpacer = new Spacer(mainToolBar, seekSlider);
266 seekSliderSpacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
267 mainToolBar->addWidget(seekSliderSpacer);
269 volumeSlider = new Phonon::VolumeSlider(this);
270 // this makes the volume slider smaller
271 volumeSlider->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
272 mainToolBar->addWidget(new Spacer(mainToolBar, volumeSlider));
274 mainToolBar->addWidget(new Spacer(mainToolBar, toolbarSearch));
276 addToolBar(mainToolBar);
279 void MainWindow::createStatusBar() {
280 currentTime = new QLabel(this);
281 statusBar()->addPermanentWidget(currentTime);
283 totalTime = new QLabel(this);
284 statusBar()->addPermanentWidget(totalTime);
286 // remove ugly borders on OSX
287 statusBar()->setStyleSheet("::item{border:0 solid}");
292 void MainWindow::readSettings() {
294 restoreGeometry(settings.value("geometry").toByteArray());
297 void MainWindow::writeSettings() {
298 // do not save geometry when in full screen
302 settings.setValue("geometry", saveGeometry());
305 void MainWindow::goBack() {
306 if ( history->size() > 1 ) {
308 QWidget *widget = history->pop();
313 void MainWindow::showWidget ( QWidget* widget ) {
315 setUpdatesEnabled(false);
317 // call hide method on the current view
318 View* oldView = dynamic_cast<View *> (views->currentWidget());
319 if (oldView != NULL) {
320 oldView->disappear();
323 // call show method on the new view
324 View* newView = dynamic_cast<View *> (widget);
325 if (newView != NULL) {
327 QMap<QString,QVariant> metadata = newView->metadata();
328 QString windowTitle = metadata.value("title").toString();
329 if (windowTitle.length())
330 windowTitle += " - ";
331 setWindowTitle(windowTitle + Constants::APP_NAME);
332 statusBar()->showMessage((metadata.value("description").toString()));
336 // backAct->setEnabled(history->size() > 1);
337 // settingsAct->setEnabled(widget != settingsView);
338 stopAct->setEnabled(widget == mediaView);
339 fullscreenAct->setEnabled(widget == mediaView);
340 compactViewAct->setEnabled(widget == mediaView);
341 webPageAct->setEnabled(widget == mediaView);
342 aboutAct->setEnabled(widget != aboutView);
344 // cool toolbar on the Mac
345 // setUnifiedTitleAndToolBarOnMac(widget == mediaView);
347 // toolbar only for the mediaView
348 mainToolBar->setVisible(widget == mediaView && !compactViewAct->isChecked());
350 history->push(widget);
351 fadeInWidget(views->currentWidget(), widget);
352 views->setCurrentWidget(widget);
354 setUpdatesEnabled(true);
357 void MainWindow::fadeInWidget(QWidget *oldWidget, QWidget *newWidget) {
358 if (faderWidget) faderWidget->close();
359 if (!oldWidget || !newWidget || oldWidget == mediaView || newWidget == mediaView) return;
360 QPixmap frozenView = QPixmap::grabWidget(oldWidget);
361 faderWidget = new FaderWidget(newWidget);
362 faderWidget->start(frozenView);
365 void MainWindow::about() {
367 aboutView = new AboutView(this);
368 views->addWidget(aboutView);
370 showWidget(aboutView);
373 void MainWindow::visitSite() {
374 QUrl url(Constants::WEBSITE);
375 statusBar()->showMessage(QString(tr("Opening %1").arg(url.toString())));
376 QDesktopServices::openUrl(url);
379 void MainWindow::donate() {
380 QUrl url(QString(Constants::WEBSITE) + "#donate");
381 statusBar()->showMessage(QString(tr("Opening %1").arg(url.toString())));
382 QDesktopServices::openUrl(url);
385 void MainWindow::quit() {
390 void MainWindow::closeEvent(QCloseEvent *event) {
392 QWidget::closeEvent(event);
395 void MainWindow::showSettings() {
397 settingsView = new SettingsView(this);
398 views->addWidget(settingsView);
400 showWidget(settingsView);
403 void MainWindow::showSearch() {
404 showWidget(searchView);
405 currentTime->clear();
409 void MainWindow::showMedia(QString query) {
411 mediaView->setMediaObject(mediaObject);
412 SearchParams *searchParams = new SearchParams();
413 searchParams->setKeywords(query);
414 mediaView->search(searchParams);
415 showWidget(mediaView);
418 void MainWindow::stateChanged(Phonon::State newState, Phonon::State /* oldState */) {
420 // qDebug() << "Phonon state: " << newState;
424 case Phonon::ErrorState:
425 if (mediaObject->errorType() == Phonon::FatalError) {
426 statusBar()->showMessage(tr("Fatal error: %1").arg(mediaObject->errorString()));
428 statusBar()->showMessage(tr("Error: %1").arg(mediaObject->errorString()));
432 case Phonon::PlayingState:
433 pauseAct->setEnabled(true);
434 pauseAct->setIcon(QtIconLoader::icon("media-pause", QIcon(":/images/pause.png")));
435 pauseAct->setText(tr("&Pause"));
436 pauseAct->setStatusTip(tr("Pause playback"));
437 skipAct->setEnabled(true);
440 case Phonon::StoppedState:
441 pauseAct->setEnabled(false);
442 skipAct->setEnabled(false);
445 case Phonon::PausedState:
446 skipAct->setEnabled(true);
447 pauseAct->setEnabled(true);
448 pauseAct->setIcon(QtIconLoader::icon("media-play", QIcon(":/images/play.png")));
449 pauseAct->setText(tr("&Play"));
450 pauseAct->setStatusTip(tr("Resume playback"));
453 case Phonon::BufferingState:
454 case Phonon::LoadingState:
455 skipAct->setEnabled(true);
456 pauseAct->setEnabled(false);
457 currentTime->clear();
466 void MainWindow::stop() {
471 void MainWindow::fullscreen() {
473 setUpdatesEnabled(false);
476 // use setShortucs instead of setShortcut
477 // the latter seems not to work
478 QList<QKeySequence> shortcuts;
479 shortcuts << QKeySequence(Qt::ALT + Qt::Key_Return);
480 fullscreenAct->setShortcuts(shortcuts);
481 fullscreenAct->setText(tr("&Full Screen"));
482 stopAct->setShortcut(QKeySequence(Qt::Key_Escape));
483 if (m_maximized) showMaximized();
486 stopAct->setShortcut(QString(""));
487 QList<QKeySequence> shortcuts;
488 // for some reason it is important that ESC comes first
489 shortcuts << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::ALT + Qt::Key_Return);
490 fullscreenAct->setShortcuts(shortcuts);
491 fullscreenAct->setText(tr("Exit &Full Screen"));
492 m_maximized = isMaximized();
494 // save geometry now, if the user quits when in full screen
495 // geometry won't be saved
501 // No compact view action when in full screen
502 compactViewAct->setVisible(m_fullscreen);
504 // Hide anything but the video
505 mediaView->setPlaylistVisible(m_fullscreen);
506 mainToolBar->setVisible(m_fullscreen);
507 statusBar()->setVisible(m_fullscreen);
508 menuBar()->setVisible(m_fullscreen);
510 m_fullscreen = !m_fullscreen;
512 setUpdatesEnabled(true);
515 void MainWindow::compactView(bool enable) {
517 setUpdatesEnabled(false);
519 // setUnifiedTitleAndToolBarOnMac(!enable);
520 mediaView->setPlaylistVisible(!enable);
521 mainToolBar->setVisible(!enable);
522 statusBar()->setVisible(!enable);
524 // ensure focus does not end up to the search box
525 // as it would steal the Space shortcut
526 toolbarSearch->setEnabled(!enable);
529 stopAct->setShortcut(QString(""));
530 QList<QKeySequence> shortcuts;
531 // for some reason it is important that ESC comes first
532 shortcuts << QKeySequence(Qt::CTRL + Qt::Key_Return) << QKeySequence(Qt::Key_Escape);
533 compactViewAct->setShortcuts(shortcuts);
535 compactViewAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Return));
536 stopAct->setShortcut(QKeySequence(Qt::Key_Escape));
539 setUpdatesEnabled(true);
542 void MainWindow::searchFocus() {
543 QWidget *view = views->currentWidget();
544 if (view == mediaView) {
545 toolbarSearch->setFocus();
549 void MainWindow::initPhonon() {
550 // Phonon initialization
551 if (mediaObject) delete mediaObject;
552 if (audioOutput) delete audioOutput;
553 mediaObject = new Phonon::MediaObject(this);
554 mediaObject->setTickInterval(100);
555 connect(mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
556 this, SLOT(stateChanged(Phonon::State, Phonon::State)));
557 connect(mediaObject, SIGNAL(tick(qint64)), this, SLOT(tick(qint64)));
558 connect(mediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64)));
559 seekSlider->setMediaObject(mediaObject);
560 audioOutput = new Phonon::AudioOutput(Phonon::VideoCategory, this);
561 volumeSlider->setAudioOutput(audioOutput);
562 Phonon::createPath(mediaObject, audioOutput);
565 void MainWindow::tick(qint64 time) {
566 QTime displayTime(0, (time / 60000) % 60, (time / 1000) % 60);
567 currentTime->setText(displayTime.toString("mm:ss"));
568 // qDebug() << "currentTime" << time << displayTime.toString("mm:ss");
571 void MainWindow::totalTimeChanged(qint64 time) {
576 QTime displayTime(0, (time / 60000) % 60, (time / 1000) % 60);
577 totalTime->setText(displayTime.toString("/ mm:ss"));
578 // qDebug() << "totalTime" << time << displayTime.toString("mm:ss");