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 // lazy initialized views
28 toolbarSearch = new SearchLineEdit(this);
29 toolbarSearch->setFont(qApp->font());
30 // toolbarSearch->setMinimumWidth(200);
31 connect(toolbarSearch, SIGNAL(search(const QString&)), searchView, SLOT(watch(const QString&)));
39 // remove that useless menu/toolbar context menu
40 this->setContextMenuPolicy(Qt::NoContextMenu);
42 // mediaView init stuff thats needs actions
43 mediaView->initialize();
45 // restore window position
48 // show the initial view
49 showWidget(searchView);
51 setCentralWidget(views);
55 QLabel* message = new QLabel(this);
56 message->setText(QString("A new version of %1 is available.").arg(Constants::APP_NAME));
57 message->setMargin(10);
58 message->setAlignment(Qt::AlignCenter);
60 message->setBackgroundRole(QPalette::ToolTipBase);
61 message->setForegroundRole(QPalette::ToolTipText);
62 message->setAutoFillBackground(true);
63 QDockWidget *dockWidget = new QDockWidget("", this, 0);
64 dockWidget->setTitleBarWidget(0);
65 dockWidget->setWidget(message);
66 dockWidget->setFeatures(QDockWidget::DockWidgetClosable);
67 addDockWidget(Qt::TopDockWidgetArea, dockWidget);
72 MainWindow::~MainWindow() {
76 void MainWindow::createActions() {
78 QMap<QString, QAction*> *actions = The::globalActions();
81 settingsAct = new QAction(tr("&Preferences..."), this);
82 settingsAct->setStatusTip(tr(QString("Configure ").append(Constants::APP_NAME).toUtf8()));
84 settingsAct->setMenuRole(QAction::PreferencesRole);
85 actions->insert("settings", settingsAct);
86 connect(settingsAct, SIGNAL(triggered()), this, SLOT(showSettings()));
89 backAct = new QAction(QIcon(":/images/go-previous.png"), tr("&Back"), this);
90 backAct->setEnabled(false);
91 backAct->setShortcut(QKeySequence(Qt::ALT + Qt::Key_Left));
92 backAct->setStatusTip(tr("Go to the previous view"));
93 actions->insert("back", backAct);
94 connect(backAct, SIGNAL(triggered()), this, SLOT(goBack()));
96 stopAct = new QAction(QtIconLoader::icon("media-stop", QIcon(":/images/stop.png")), tr("&Stop"), this);
97 stopAct->setStatusTip(tr("Stop playback and go back to the search view"));
98 stopAct->setShortcut(QKeySequence(Qt::Key_Escape));
99 actions->insert("stop", stopAct);
100 connect(stopAct, SIGNAL(triggered()), this, SLOT(stop()));
102 skipAct = new QAction(QtIconLoader::icon("media-skip-forward", QIcon(":/images/skip.png")), tr("S&kip"), this);
103 skipAct->setStatusTip(tr("Skip to the next video"));
104 skipAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Right));
105 skipAct->setEnabled(false);
106 actions->insert("skip", skipAct);
107 connect(skipAct, SIGNAL(triggered()), mediaView, SLOT(skip()));
109 pauseAct = new QAction(QtIconLoader::icon("media-pause", QIcon(":/images/pause.png")), tr("&Pause"), this);
110 pauseAct->setStatusTip(tr("Pause playback"));
111 pauseAct->setShortcut(QKeySequence(Qt::Key_Space));
112 pauseAct->setEnabled(false);
113 actions->insert("pause", pauseAct);
114 connect(pauseAct, SIGNAL(triggered()), mediaView, SLOT(pause()));
116 fullscreenAct = new QAction(QtIconLoader::icon("view-fullscreen", QIcon(":/images/view-fullscreen.png")), tr("&Full Screen"), this);
117 fullscreenAct->setStatusTip(tr("Go full screen"));
118 fullscreenAct->setShortcut(QKeySequence(Qt::ALT + Qt::Key_Enter));
119 fullscreenAct->setShortcutContext(Qt::ApplicationShortcut);
120 actions->insert("fullscreen", fullscreenAct);
121 connect(fullscreenAct, SIGNAL(triggered()), this, SLOT(fullscreen()));
124 // icon should be document-save but it is ugly
125 downloadAct = new QAction(QtIconLoader::icon("go-down", QIcon(":/images/go-down.png")), tr("&Download"), this);
126 downloadAct->setStatusTip(tr("Download this video"));
127 downloadAct->setShortcut(tr("Ctrl+S"));
128 actions.insert("download", downloadAct);
129 connect(downloadAct, SIGNAL(triggered()), this, SLOT(download()));
132 webPageAct = new QAction(QtIconLoader::icon("internet-web-browser", QIcon(":/images/internet-web-browser.png")), tr("&YouTube"), this);
133 webPageAct->setStatusTip(tr("Open the YouTube video page"));
134 webPageAct->setShortcut(tr("Ctrl+Y"));
135 webPageAct->setEnabled(false);
136 actions->insert("webpage", webPageAct);
137 connect(webPageAct, SIGNAL(triggered()), mediaView, SLOT(openWebPage()));
139 removeAct = new QAction(tr("&Remove"), this);
140 removeAct->setStatusTip(tr("Remove the selected videos from the playlist"));
141 QList<QKeySequence> shortcuts;
142 shortcuts << QKeySequence("Del") << QKeySequence("Backspace");
143 removeAct->setShortcuts(shortcuts);
144 removeAct->setEnabled(false);
145 actions->insert("remove", removeAct);
146 connect(removeAct, SIGNAL(triggered()), mediaView, SLOT(removeSelected()));
148 moveUpAct = new QAction(QtIconLoader::icon("go-up", QIcon(":/images/go-up.png")), tr("Move &Up"), this);
149 moveUpAct->setStatusTip(tr("Move up the selected videos in the playlist"));
150 moveUpAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Up));
151 moveUpAct->setEnabled(false);
152 actions->insert("moveUp", moveUpAct);
153 connect(moveUpAct, SIGNAL(triggered()), mediaView, SLOT(moveUpSelected()));
155 moveDownAct = new QAction(QtIconLoader::icon("go-down", QIcon(":/images/go-down.png")), tr("Move &Down"), this);
156 moveDownAct->setStatusTip(tr("Move down the selected videos in the playlist"));
157 moveDownAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Down));
158 moveDownAct->setEnabled(false);
159 actions->insert("moveDown", moveDownAct);
160 connect(moveDownAct, SIGNAL(triggered()), mediaView, SLOT(moveDownSelected()));
162 quitAct = new QAction(tr("&Quit"), this);
163 quitAct->setMenuRole(QAction::QuitRole);
164 quitAct->setShortcut(tr("Ctrl+Q"));
165 quitAct->setStatusTip(tr("Bye"));
166 actions->insert("quit", quitAct);
167 connect(quitAct, SIGNAL(triggered()), this, SLOT(quit()));
169 siteAct = new QAction(tr("&Website"), this);
170 siteAct->setShortcut(QKeySequence::HelpContents);
171 siteAct->setStatusTip(tr("%1 on the Web").arg(Constants::APP_NAME));
172 actions->insert("site", siteAct);
173 connect(siteAct, SIGNAL(triggered()), this, SLOT(visitSite()));
175 donateAct = new QAction(tr("&Donate via PayPal"), this);
176 donateAct->setStatusTip(tr("Please support the continued development of %1").arg(Constants::APP_NAME));
177 actions->insert("donate", donateAct);
178 connect(donateAct, SIGNAL(triggered()), this, SLOT(donate()));
180 aboutAct = new QAction(tr("&About"), this);
181 aboutAct->setMenuRole(QAction::AboutRole);
182 aboutAct->setStatusTip(tr("Info about %1").arg(Constants::APP_NAME));
183 actions->insert("about", aboutAct);
184 connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
186 searchFocusAct = new QAction(tr("&Search"), this);
187 searchFocusAct->setShortcut(QKeySequence::Find);
188 actions->insert("search", searchFocusAct);
189 connect(searchFocusAct, SIGNAL(triggered()), this, SLOT(searchFocus()));
190 addAction(searchFocusAct);
192 // common action properties
193 foreach (QAction *action, actions->values()) {
195 // unexperienced users tend to keep keys pressed for a "long" time
196 action->setAutoRepeat(false);
197 action->setToolTip(action->statusTip());
199 // make the actions work when video is fullscreen
200 action->setShortcutContext(Qt::ApplicationShortcut);
203 // OSX does not use icons in menus
204 action->setIconVisibleInMenu(false);
211 void MainWindow::createMenus() {
213 QMap<QString, QMenu*> *menus = The::globalMenus();
215 fileMenu = menuBar()->addMenu(tr("&Application"));
216 // menus->insert("file", fileMenu);
218 fileMenu->addAction(settingsAct);
219 fileMenu->addSeparator();
221 fileMenu->addAction(quitAct);
223 playlistMenu = menuBar()->addMenu(tr("&Playlist"));
224 menus->insert("playlist", playlistMenu);
225 playlistMenu->addAction(removeAct);
226 playlistMenu->addSeparator();
227 playlistMenu->addAction(moveUpAct);
228 playlistMenu->addAction(moveDownAct);
230 viewMenu = menuBar()->addMenu(tr("&Video"));
231 menus->insert("video", viewMenu);
232 // viewMenu->addAction(backAct);
233 viewMenu->addAction(stopAct);
234 viewMenu->addAction(pauseAct);
235 viewMenu->addAction(skipAct);
236 viewMenu->addSeparator();
237 viewMenu->addAction(webPageAct);
238 viewMenu->addSeparator();
239 viewMenu->addAction(fullscreenAct);
241 helpMenu = menuBar()->addMenu(tr("&Help"));
242 helpMenu->addAction(siteAct);
243 helpMenu->addAction(donateAct);
244 helpMenu->addAction(aboutAct);
247 void MainWindow::createToolBars() {
249 setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
251 mainToolBar = new QToolBar(this);
252 mainToolBar->setFloatable(false);
253 mainToolBar->setMovable(false);
256 smallerFont.setPointSize(smallerFont.pointSize()*.85);
257 mainToolBar->setFont(smallerFont);
259 mainToolBar->setIconSize(QSize(32,32));
260 // mainToolBar->addAction(backAct);
261 mainToolBar->addAction(stopAct);
262 mainToolBar->addAction(pauseAct);
263 mainToolBar->addAction(skipAct);
264 mainToolBar->addAction(fullscreenAct);
266 seekSlider = new Phonon::SeekSlider(this);
267 seekSlider->setIconVisible(false);
268 Spacer *seekSliderSpacer = new Spacer(mainToolBar, seekSlider);
269 seekSliderSpacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
270 mainToolBar->addWidget(seekSliderSpacer);
272 volumeSlider = new Phonon::VolumeSlider(this);
273 // this makes the volume slider smaller
274 volumeSlider->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
275 mainToolBar->addWidget(new Spacer(mainToolBar, volumeSlider));
277 mainToolBar->addWidget(new Spacer(mainToolBar, toolbarSearch));
279 addToolBar(mainToolBar);
282 void MainWindow::createStatusBar() {
283 currentTime = new QLabel(this);
284 statusBar()->addPermanentWidget(currentTime);
285 totalTime = new QLabel(this);
286 statusBar()->addPermanentWidget(totalTime);
290 void MainWindow::readSettings() {
292 restoreGeometry(settings.value("geometry").toByteArray());
295 void MainWindow::writeSettings() {
297 settings.setValue("geometry", saveGeometry());
300 void MainWindow::goBack() {
301 if ( history->size() > 1 ) {
303 QWidget *widget = history->pop();
308 void MainWindow::showWidget ( QWidget* widget ) {
310 // call hide method on the current view
311 View* oldView = dynamic_cast<View *> (views->currentWidget());
312 if (oldView != NULL) {
313 oldView->disappear();
316 // call show method on the new view
317 View* newView = dynamic_cast<View *> (widget);
318 if (newView != NULL) {
320 QMap<QString,QVariant> metadata = newView->metadata();
321 QString windowTitle = metadata.value("title").toString();
322 if (windowTitle.length())
323 windowTitle += " - ";
324 setWindowTitle(windowTitle + Constants::APP_NAME);
325 statusBar()->showMessage((metadata.value("description").toString()));
329 // backAct->setEnabled(history->size() > 1);
330 // settingsAct->setEnabled(widget != settingsView);
331 stopAct->setEnabled(widget == mediaView);
332 fullscreenAct->setEnabled(widget == mediaView);
333 webPageAct->setEnabled(widget == mediaView);
334 aboutAct->setEnabled(widget != aboutView);
336 // cool toolbar on the Mac
337 setUnifiedTitleAndToolBarOnMac(widget == mediaView);
339 // toolbar only for the mediaView
340 mainToolBar->setVisible(widget == mediaView);
342 history->push(widget);
343 fadeInWidget(views->currentWidget(), widget);
344 views->setCurrentWidget(widget);
348 void MainWindow::fadeInWidget(QWidget *oldWidget, QWidget *newWidget) {
349 if (faderWidget) faderWidget->close();
350 if (!oldWidget || !newWidget || oldWidget == mediaView || newWidget == mediaView) return;
351 QPixmap frozenView = QPixmap::grabWidget(oldWidget);
352 faderWidget = new FaderWidget(newWidget);
353 faderWidget->start(frozenView);
356 void MainWindow::about() {
358 aboutView = new AboutView(this);
359 views->addWidget(aboutView);
361 showWidget(aboutView);
364 void MainWindow::visitSite() {
365 QUrl url(Constants::WEBSITE);
366 statusBar()->showMessage(QString(tr("Opening %1").arg(url.toString())));
367 QDesktopServices::openUrl(url);
370 void MainWindow::donate() {
371 QUrl url(QString(Constants::WEBSITE) + "#donate");
372 statusBar()->showMessage(QString(tr("Opening %1").arg(url.toString())));
373 QDesktopServices::openUrl(url);
376 void MainWindow::quit() {
381 void MainWindow::closeEvent(QCloseEvent *event) {
383 QWidget::closeEvent(event);
386 void MainWindow::showSettings() {
388 settingsView = new SettingsView(this);
389 views->addWidget(settingsView);
391 showWidget(settingsView);
394 void MainWindow::showSearch() {
395 showWidget(searchView);
396 currentTime->clear();
400 void MainWindow::showMedia(QString query) {
402 mediaView->setMediaObject(mediaObject);
403 SearchParams *searchParams = new SearchParams();
404 searchParams->setKeywords(query);
405 mediaView->search(searchParams);
406 showWidget(mediaView);
409 void MainWindow::stateChanged(Phonon::State newState, Phonon::State /* oldState */) {
411 // qDebug() << "Phonon state: " << newState;
415 case Phonon::ErrorState:
416 if (mediaObject->errorType() == Phonon::FatalError) {
417 statusBar()->showMessage(tr("Fatal error: %1").arg(mediaObject->errorString()));
419 statusBar()->showMessage(tr("Error: %1").arg(mediaObject->errorString()));
423 case Phonon::PlayingState:
424 pauseAct->setEnabled(true);
425 pauseAct->setIcon(QtIconLoader::icon("media-pause", QIcon(":/images/pause.png")));
426 pauseAct->setText(tr("&Pause"));
427 pauseAct->setStatusTip(tr("Pause playback"));
428 skipAct->setEnabled(true);
431 case Phonon::StoppedState:
432 pauseAct->setEnabled(false);
433 skipAct->setEnabled(false);
436 case Phonon::PausedState:
437 skipAct->setEnabled(true);
438 pauseAct->setEnabled(true);
439 pauseAct->setIcon(QtIconLoader::icon("media-play", QIcon(":/images/play.png")));
440 pauseAct->setText(tr("&Play"));
441 pauseAct->setStatusTip(tr("Resume playback"));
444 case Phonon::BufferingState:
445 case Phonon::LoadingState:
446 skipAct->setEnabled(true);
447 pauseAct->setEnabled(false);
448 currentTime->clear();
457 void MainWindow::stop() {
462 void MainWindow::fullscreen() {
464 mediaView->exitFullscreen();
465 fullscreenAct->setShortcut(QKeySequence(Qt::ALT + Qt::Key_Enter));
466 fullscreenAct->setText(tr("&Full Screen"));
467 stopAct->setShortcut(QKeySequence(Qt::Key_Escape));
469 mediaView->fullscreen();
470 stopAct->setShortcut(QString(""));
471 fullscreenAct->setShortcut(QKeySequence(Qt::Key_Escape));
472 fullscreenAct->setText(tr("Exit &Full Screen"));
474 m_fullscreen = !m_fullscreen;
477 void MainWindow::searchFocus() {
478 QWidget *view = views->currentWidget();
479 if (view == mediaView) {
480 toolbarSearch->setFocus();
484 void MainWindow::initPhonon() {
485 // Phonon initialization
486 if (mediaObject) delete mediaObject;
487 if (audioOutput) delete audioOutput;
488 mediaObject = new Phonon::MediaObject(this);
489 mediaObject->setTickInterval(100);
490 connect(mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
491 this, SLOT(stateChanged(Phonon::State, Phonon::State)));
492 connect(mediaObject, SIGNAL(tick(qint64)), this, SLOT(tick(qint64)));
493 connect(mediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64)));
494 seekSlider->setMediaObject(mediaObject);
495 audioOutput = new Phonon::AudioOutput(Phonon::VideoCategory, this);
496 volumeSlider->setAudioOutput(audioOutput);
497 Phonon::createPath(mediaObject, audioOutput);
500 void MainWindow::tick(qint64 time) {
501 QTime displayTime(0, (time / 60000) % 60, (time / 1000) % 60);
502 currentTime->setText(displayTime.toString("mm:ss"));
503 // qDebug() << "currentTime" << time << displayTime.toString("mm:ss");
506 void MainWindow::totalTimeChanged(qint64 time) {
511 QTime displayTime(0, (time / 60000) % 60, (time / 1000) % 60);
512 totalTime->setText(displayTime.toString("/ mm:ss"));
513 // qDebug() << "totalTime" << time << displayTime.toString("mm:ss");