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 toolbarSearch->setMinimumWidth(toolbarSearch->fontInfo().pixelSize()*15);
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);
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-playback-stop", QIcon(":/images/stop.png")), tr("&Stop"), this);
79 stopAct->setStatusTip(tr("Stop playback and go back to the search view"));
80 stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
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->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_Right) << QKeySequence(Qt::Key_MediaNext));
87 skipAct->setEnabled(false);
88 actions->insert("skip", skipAct);
89 connect(skipAct, SIGNAL(triggered()), mediaView, SLOT(skip()));
91 pauseAct = new QAction(QtIconLoader::icon("media-playback-pause", QIcon(":/images/pause.png")), tr("&Pause"), this);
92 pauseAct->setStatusTip(tr("Pause playback"));
93 pauseAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Space) << QKeySequence(Qt::Key_MediaPlay));
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 downloadAct->setEnabled(false);
120 actions->insert("download", downloadAct);
121 connect(downloadAct, SIGNAL(triggered()), this, SLOT(download()));
124 webPageAct = new QAction(tr("&YouTube"), this);
125 webPageAct->setStatusTip(tr("Open the YouTube video page"));
126 webPageAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Y));
127 webPageAct->setEnabled(false);
128 actions->insert("webpage", webPageAct);
129 connect(webPageAct, SIGNAL(triggered()), mediaView, SLOT(openWebPage()));
131 removeAct = new QAction(tr("&Remove"), this);
132 removeAct->setStatusTip(tr("Remove the selected videos from the playlist"));
133 removeAct->setShortcuts(QList<QKeySequence>() << QKeySequence("Del") << QKeySequence("Backspace"));
134 removeAct->setEnabled(false);
135 actions->insert("remove", removeAct);
136 connect(removeAct, SIGNAL(triggered()), mediaView, SLOT(removeSelected()));
138 moveUpAct = new QAction(QtIconLoader::icon("go-up", QIcon(":/images/go-up.png")), tr("Move &Up"), this);
139 moveUpAct->setStatusTip(tr("Move up the selected videos in the playlist"));
140 moveUpAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Up));
141 moveUpAct->setEnabled(false);
142 actions->insert("moveUp", moveUpAct);
143 connect(moveUpAct, SIGNAL(triggered()), mediaView, SLOT(moveUpSelected()));
145 moveDownAct = new QAction(QtIconLoader::icon("go-down", QIcon(":/images/go-down.png")), tr("Move &Down"), this);
146 moveDownAct->setStatusTip(tr("Move down the selected videos in the playlist"));
147 moveDownAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Down));
148 moveDownAct->setEnabled(false);
149 actions->insert("moveDown", moveDownAct);
150 connect(moveDownAct, SIGNAL(triggered()), mediaView, SLOT(moveDownSelected()));
152 quitAct = new QAction(tr("&Quit"), this);
153 quitAct->setMenuRole(QAction::QuitRole);
154 quitAct->setShortcuts(QList<QKeySequence>() << QKeySequence(tr("Ctrl+Q")) << QKeySequence(Qt::CTRL + Qt::Key_W));
155 quitAct->setStatusTip(tr("Bye"));
156 actions->insert("quit", quitAct);
157 connect(quitAct, SIGNAL(triggered()), this, SLOT(quit()));
159 siteAct = new QAction(tr("&Website"), this);
160 siteAct->setShortcut(QKeySequence::HelpContents);
161 siteAct->setStatusTip(tr("%1 on the Web").arg(Constants::APP_NAME));
162 actions->insert("site", siteAct);
163 connect(siteAct, SIGNAL(triggered()), this, SLOT(visitSite()));
165 donateAct = new QAction(tr("&Donate via PayPal"), this);
166 donateAct->setStatusTip(tr("Please support the continued development of %1").arg(Constants::APP_NAME));
167 actions->insert("donate", donateAct);
168 connect(donateAct, SIGNAL(triggered()), this, SLOT(donate()));
170 aboutAct = new QAction(tr("&About"), this);
171 aboutAct->setMenuRole(QAction::AboutRole);
172 aboutAct->setStatusTip(tr("Info about %1").arg(Constants::APP_NAME));
173 actions->insert("about", aboutAct);
174 connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
178 searchFocusAct = new QAction(this);
179 searchFocusAct->setShortcut(QKeySequence::Find);
180 searchFocusAct->setStatusTip(tr("Search"));
181 actions->insert("search", searchFocusAct);
182 connect(searchFocusAct, SIGNAL(triggered()), this, SLOT(searchFocus()));
183 addAction(searchFocusAct);
185 volumeUpAct = new QAction(this);
186 volumeUpAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_Plus) << QKeySequence(Qt::Key_VolumeUp));
187 actions->insert("volume-up", volumeUpAct);
188 connect(volumeUpAct, SIGNAL(triggered()), this, SLOT(volumeUp()));
189 addAction(volumeUpAct);
191 volumeDownAct = new QAction(this);
192 volumeDownAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_Minus) << QKeySequence(Qt::Key_VolumeDown));
193 actions->insert("volume-down", volumeDownAct);
194 connect(volumeDownAct, SIGNAL(triggered()), this, SLOT(volumeDown()));
195 addAction(volumeDownAct);
197 volumeMuteAct = new QAction(this);
198 volumeMuteAct->setStatusTip(tr("Mute volume"));
199 volumeMuteAct->setShortcuts(QList<QKeySequence>() << QKeySequence(tr("Ctrl+M")) << QKeySequence(Qt::Key_VolumeMute));
200 actions->insert("volume-mute", volumeMuteAct);
201 connect(volumeMuteAct, SIGNAL(triggered()), this, SLOT(volumeMute()));
202 addAction(volumeMuteAct);
204 QAction *hdAct = new QAction(this);
205 hdAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_H));
206 hdAct->setIcon(createHDIcon());
207 hdAct->setCheckable(true);
208 actions->insert("hd", hdAct);
210 connect(hdAct, SIGNAL(toggled(bool)), this, SLOT(saveHdSetting(bool)));
213 // common action properties
214 foreach (QAction *action, actions->values()) {
216 // add actions to the MainWindow so that they work
217 // when the menu is hidden
221 // unexperienced users tend to keep keys pressed for a "long" time
222 action->setAutoRepeat(false);
224 // set to something more meaningful then the toolbar text
225 // HELP! how to remove tooltips altogether?!
226 if (!action->statusTip().isEmpty())
227 action->setToolTip(action->statusTip());
229 // show keyboard shortcuts in the status bar
230 if (!action->shortcut().isEmpty())
231 action->setStatusTip(action->statusTip() + " (" + action->shortcut().toString(QKeySequence::NativeText) + ")");
233 // make the actions work when video is fullscreen
234 action->setShortcutContext(Qt::ApplicationShortcut);
237 action->setIconVisibleInMenu(false);
243 void MainWindow::createMenus() {
245 QMap<QString, QMenu*> *menus = The::globalMenus();
248 fileMenu = menuBar()->addMenu(tr("&Application"));
249 // menus->insert("file", fileMenu);
250 // fileMenu->addAction(settingsAct);
251 fileMenu->addSeparator();
252 fileMenu->addAction(quitAct);
255 playlistMenu = menuBar()->addMenu(tr("&Playlist"));
256 menus->insert("playlist", playlistMenu);
257 playlistMenu->addAction(removeAct);
258 playlistMenu->addSeparator();
259 playlistMenu->addAction(moveUpAct);
260 playlistMenu->addAction(moveDownAct);
262 viewMenu = menuBar()->addMenu(tr("&Video"));
263 menus->insert("video", viewMenu);
264 // viewMenu->addAction(backAct);
265 viewMenu->addAction(stopAct);
266 viewMenu->addAction(pauseAct);
267 viewMenu->addAction(skipAct);
268 viewMenu->addSeparator();
269 viewMenu->addAction(webPageAct);
270 viewMenu->addSeparator();
271 // viewMenu->addAction(downloadAct);
272 viewMenu->addAction(compactViewAct);
273 viewMenu->addAction(fullscreenAct);
275 helpMenu = menuBar()->addMenu(tr("&Help"));
276 helpMenu->addAction(siteAct);
277 helpMenu->addAction(donateAct);
278 helpMenu->addAction(aboutAct);
281 void MainWindow::createToolBars() {
283 mainToolBar = new QToolBar(this);
284 mainToolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
285 mainToolBar->setFloatable(false);
286 mainToolBar->setMovable(false);
289 smallerFont.setPointSize(smallerFont.pointSize()*.85);
290 QFontInfo fontInfo(smallerFont);
291 if (fontInfo.pixelSize() < 10) {
292 smallerFont.setPixelSize(10);
294 mainToolBar->setFont(smallerFont);
296 mainToolBar->setIconSize(QSize(32,32));
297 // mainToolBar->addAction(backAct);
298 mainToolBar->addAction(stopAct);
299 mainToolBar->addAction(pauseAct);
300 mainToolBar->addAction(skipAct);
301 mainToolBar->addAction(fullscreenAct);
303 seekSlider = new Phonon::SeekSlider(this);
304 seekSlider->setIconVisible(false);
305 Spacer *seekSliderSpacer = new Spacer(mainToolBar, seekSlider);
306 seekSliderSpacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
307 mainToolBar->addWidget(seekSliderSpacer);
309 volumeSlider = new Phonon::VolumeSlider(this);
310 // qDebug() << volumeSlider->children();
311 // status tip for the volume slider
312 QSlider* volumeQSlider = volumeSlider->findChild<QSlider*>();
314 volumeQSlider->setStatusTip(tr("Press %1 to raise the volume, %2 to lower it").arg(
315 volumeUpAct->shortcut().toString(QKeySequence::NativeText), volumeDownAct->shortcut().toString(QKeySequence::NativeText)));
316 // status tip for the mute button
317 QToolButton* muteToolButton = volumeSlider->findChild<QToolButton*>();
319 muteToolButton->setStatusTip(volumeMuteAct->statusTip());
320 // this makes the volume slider smaller
321 volumeSlider->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
322 mainToolBar->addWidget(new Spacer(mainToolBar, volumeSlider));
324 toolbarSearch->setStatusTip(searchFocusAct->statusTip());
325 mainToolBar->addWidget(new Spacer(mainToolBar, toolbarSearch));
327 addToolBar(mainToolBar);
330 void MainWindow::createStatusBar() {
331 currentTime = new QLabel(this);
332 statusBar()->addPermanentWidget(currentTime);
334 totalTime = new QLabel(this);
335 statusBar()->addPermanentWidget(totalTime);
337 // remove ugly borders on OSX
338 // and remove some excessive padding
339 statusBar()->setStyleSheet("::item{border:0 solid} QStatusBar, QToolBar {padding:0;margin:0} QToolButton {padding:1px}");
341 QToolBar *toolBar = new QToolBar(this);
342 int iconHeight = 24; // statusBar()->height();
343 int iconWidth = 36; // iconHeight * 3 / 2;
344 toolBar->setIconSize(QSize(iconWidth, iconHeight));
345 toolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
346 toolBar->addAction(The::globalActions()->value("hd"));
347 statusBar()->addPermanentWidget(toolBar);
352 void MainWindow::readSettings() {
354 restoreGeometry(settings.value("geometry").toByteArray());
355 The::globalActions()->value("hd")->setChecked(settings.value("hd").toBool());
358 void MainWindow::writeSettings() {
359 // do not save geometry when in full screen
363 settings.setValue("geometry", saveGeometry());
364 mediaView->saveSplitterState();
367 void MainWindow::goBack() {
368 if ( history->size() > 1 ) {
370 QWidget *widget = history->pop();
375 void MainWindow::showWidget ( QWidget* widget ) {
377 setUpdatesEnabled(false);
379 // call hide method on the current view
380 View* oldView = dynamic_cast<View *> (views->currentWidget());
381 if (oldView != NULL) {
382 oldView->disappear();
385 // call show method on the new view
386 View* newView = dynamic_cast<View *> (widget);
387 if (newView != NULL) {
389 QMap<QString,QVariant> metadata = newView->metadata();
390 QString windowTitle = metadata.value("title").toString();
391 if (windowTitle.length())
392 windowTitle += " - ";
393 setWindowTitle(windowTitle + Constants::APP_NAME);
394 statusBar()->showMessage((metadata.value("description").toString()));
398 // backAct->setEnabled(history->size() > 1);
399 // settingsAct->setEnabled(widget != settingsView);
400 stopAct->setEnabled(widget == mediaView);
401 fullscreenAct->setEnabled(widget == mediaView);
402 compactViewAct->setEnabled(widget == mediaView);
403 webPageAct->setEnabled(widget == mediaView);
404 aboutAct->setEnabled(widget != aboutView);
407 // this is not the best place to enable downloads, but the user is informed
408 // if there really is no video is playing
409 downloadAct->setEnabled(widget == mediaView);
412 // cool toolbar on the Mac
413 // setUnifiedTitleAndToolBarOnMac(widget == mediaView);
415 // toolbar only for the mediaView
416 mainToolBar->setVisible(widget == mediaView && !compactViewAct->isChecked());
418 setUpdatesEnabled(true);
420 history->push(widget);
423 // crossfade only on OSX
424 // where we can be sure of video performance
425 fadeInWidget(views->currentWidget(), widget);
428 views->setCurrentWidget(widget);
432 void MainWindow::fadeInWidget(QWidget *oldWidget, QWidget *newWidget) {
433 if (faderWidget) faderWidget->close();
434 if (oldWidget == mediaView || newWidget == mediaView) return;
435 QPixmap frozenView = QPixmap::grabWidget(oldWidget);
436 faderWidget = new FaderWidget(newWidget);
437 faderWidget->start(frozenView);
440 void MainWindow::about() {
442 aboutView = new AboutView(this);
443 views->addWidget(aboutView);
445 showWidget(aboutView);
448 void MainWindow::visitSite() {
449 QUrl url(Constants::WEBSITE);
450 statusBar()->showMessage(QString(tr("Opening %1").arg(url.toString())));
451 QDesktopServices::openUrl(url);
454 void MainWindow::donate() {
455 QUrl url(QString(Constants::WEBSITE) + "#donate");
456 statusBar()->showMessage(QString(tr("Opening %1").arg(url.toString())));
457 QDesktopServices::openUrl(url);
460 void MainWindow::quit() {
465 void MainWindow::closeEvent(QCloseEvent *event) {
467 QWidget::closeEvent(event);
470 void MainWindow::showSettings() {
472 settingsView = new SettingsView(this);
473 views->addWidget(settingsView);
475 showWidget(settingsView);
478 void MainWindow::showSearch() {
479 showWidget(searchView);
480 currentTime->clear();
484 void MainWindow::showMedia(QString query) {
486 mediaView->setMediaObject(mediaObject);
487 SearchParams *searchParams = new SearchParams();
488 searchParams->setKeywords(query);
489 mediaView->search(searchParams);
490 showWidget(mediaView);
493 void MainWindow::stateChanged(Phonon::State newState, Phonon::State /* oldState */) {
495 // qDebug() << "Phonon state: " << newState;
499 case Phonon::ErrorState:
500 if (mediaObject->errorType() == Phonon::FatalError) {
501 statusBar()->showMessage(tr("Fatal error: %1").arg(mediaObject->errorString()));
503 statusBar()->showMessage(tr("Error: %1").arg(mediaObject->errorString()));
507 case Phonon::PlayingState:
508 pauseAct->setEnabled(true);
509 pauseAct->setIcon(QtIconLoader::icon("media-playback-pause", QIcon(":/images/pause.png")));
510 pauseAct->setText(tr("&Pause"));
511 pauseAct->setStatusTip(tr("Pause playback") + " (" + pauseAct->shortcut().toString(QKeySequence::NativeText) + ")");
512 skipAct->setEnabled(true);
515 case Phonon::StoppedState:
516 pauseAct->setEnabled(false);
517 skipAct->setEnabled(false);
520 case Phonon::PausedState:
521 skipAct->setEnabled(true);
522 pauseAct->setEnabled(true);
523 pauseAct->setIcon(QtIconLoader::icon("media-playback-start", QIcon(":/images/play.png")));
524 pauseAct->setText(tr("&Play"));
525 pauseAct->setStatusTip(tr("Resume playback") + " (" + pauseAct->shortcut().toString(QKeySequence::NativeText) + ")");
528 case Phonon::BufferingState:
529 case Phonon::LoadingState:
530 skipAct->setEnabled(true);
531 pauseAct->setEnabled(false);
532 currentTime->clear();
541 void MainWindow::stop() {
546 void MainWindow::fullscreen() {
548 setUpdatesEnabled(false);
551 // use setShortucs instead of setShortcut
552 // the latter seems not to work
553 fullscreenAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::ALT + Qt::Key_Return));
554 fullscreenAct->setText(tr("&Full Screen"));
555 stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
556 if (m_maximized) showMaximized();
558 // Make sure the window has focus (Mac)
561 stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_MediaStop));
562 fullscreenAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::ALT + Qt::Key_Return));
563 fullscreenAct->setText(tr("Exit &Full Screen"));
564 m_maximized = isMaximized();
566 // save geometry now, if the user quits when in full screen
567 // geometry won't be saved
573 // No compact view action when in full screen
574 compactViewAct->setVisible(m_fullscreen);
575 // Also no Youtube action since it opens a new window
576 webPageAct->setVisible(m_fullscreen);
578 // Hide anything but the video
579 mediaView->setPlaylistVisible(m_fullscreen);
580 mainToolBar->setVisible(m_fullscreen);
581 statusBar()->setVisible(m_fullscreen);
582 menuBar()->setVisible(m_fullscreen);
584 // workaround: prevent focus on the search bar
585 // it steals the Space key needed for Play/Pause
586 mainToolBar->setEnabled(m_fullscreen);
588 m_fullscreen = !m_fullscreen;
590 setUpdatesEnabled(true);
593 void MainWindow::compactView(bool enable) {
595 setUpdatesEnabled(false);
597 // setUnifiedTitleAndToolBarOnMac(!enable);
598 mediaView->setPlaylistVisible(!enable);
599 mainToolBar->setVisible(!enable);
600 statusBar()->setVisible(!enable);
604 menuBar()->setVisible(!enable);
607 // ensure focus does not end up to the search box
608 // as it would steal the Space shortcut
609 toolbarSearch->setEnabled(!enable);
612 stopAct->setShortcut(QString(""));
613 QList<QKeySequence> shortcuts;
614 // for some reason it is important that ESC comes first
615 shortcuts << QKeySequence(Qt::CTRL + Qt::Key_Return) << QKeySequence(Qt::Key_Escape);
616 compactViewAct->setShortcuts(shortcuts);
618 compactViewAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Return));
619 stopAct->setShortcut(QKeySequence(Qt::Key_Escape));
622 setUpdatesEnabled(true);
625 void MainWindow::searchFocus() {
626 QWidget *view = views->currentWidget();
627 if (view == mediaView) {
628 toolbarSearch->setFocus();
632 void MainWindow::initPhonon() {
633 // Phonon initialization
634 if (mediaObject) delete mediaObject;
635 if (audioOutput) delete audioOutput;
636 mediaObject = new Phonon::MediaObject(this);
637 mediaObject->setTickInterval(100);
638 connect(mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
639 this, SLOT(stateChanged(Phonon::State, Phonon::State)));
640 connect(mediaObject, SIGNAL(tick(qint64)), this, SLOT(tick(qint64)));
641 connect(mediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64)));
642 seekSlider->setMediaObject(mediaObject);
643 audioOutput = new Phonon::AudioOutput(Phonon::VideoCategory, this);
644 connect(audioOutput, SIGNAL(volumeChanged(qreal)), this, SLOT(volumeChanged(qreal)));
645 connect(audioOutput, SIGNAL(mutedChanged(bool)), this, SLOT(volumeMutedChanged(bool)));
646 volumeSlider->setAudioOutput(audioOutput);
647 Phonon::createPath(mediaObject, audioOutput);
650 void MainWindow::tick(qint64 time) {
652 currentTime->clear();
655 QTime displayTime(0, (time / 60000) % 60, (time / 1000) % 60);
656 currentTime->setText(displayTime.toString("mm:ss"));
658 // remaining time tooltip
659 int remainingTimeInt = mediaObject->remainingTime();
660 QTime remainingTime(0, (remainingTimeInt / 60000) % 60, (remainingTimeInt / 1000) % 60);
661 currentTime->setStatusTip(tr("Remaining time: %1").arg(remainingTime.toString("mm:ss")));
663 // qDebug() << "currentTime" << time << displayTime.toString("mm:ss");
666 void MainWindow::totalTimeChanged(qint64 time) {
671 QTime displayTime(0, (time / 60000) % 60, (time / 1000) % 60);
672 totalTime->setText(displayTime.toString("/ mm:ss"));
673 // qDebug() << "totalTime" << time << displayTime.toString("mm:ss");
676 void MainWindow::volumeUp() {
677 qreal newVolume = volumeSlider->audioOutput()->volume() + .1;
678 if (newVolume > volumeSlider->maximumVolume())
679 newVolume = volumeSlider->maximumVolume();
680 volumeSlider->audioOutput()->setVolume(newVolume);
683 void MainWindow::volumeDown() {
684 qreal newVolume = volumeSlider->audioOutput()->volume() - .1;
687 volumeSlider->audioOutput()->setVolume(newVolume);
690 void MainWindow::volumeMute() {
691 volumeSlider->audioOutput()->setMuted(!volumeSlider->audioOutput()->isMuted());
694 void MainWindow::volumeChanged(qreal newVolume) {
695 // automatically unmute when volume changes
696 if (volumeSlider->audioOutput()->isMuted())
697 volumeSlider->audioOutput()->setMuted(false);
698 statusBar()->showMessage(tr("Volume at %1%").arg(newVolume*100));
701 void MainWindow::volumeMutedChanged(bool muted) {
703 statusBar()->showMessage(tr("Volume is muted"));
705 statusBar()->showMessage(tr("Volume is unmuted"));
709 void MainWindow::abortDownload() {
710 QProgressDialog* dlg = dynamic_cast<QProgressDialog*>(this->sender());
711 QMap<QNetworkReply*, DownloadResource>::iterator cur;
712 QMap<QNetworkReply*, DownloadResource>::iterator end;
713 // locate the DownloadResource by its dialog address and trigger abortion
714 for(cur=m_downloads.begin(), end=m_downloads.end(); cur!=end; cur++){
715 if(cur.value().dialog == dlg) cur.key()->abort();
719 void MainWindow::download() {
720 if(mediaObject == NULL || mediaObject->currentSource().url().isEmpty()){
721 // complain unless video source apperas to be valid
722 QMessageBox::critical(this, tr("No Video playing"), tr("You must first play the video you intent to download !"));
725 QString filename = QFileDialog::getSaveFileName(this,
726 tr("Save video as..."),
727 tr("minitube video.mp4"),
728 "Video File(*.avi *.mp4)"
730 if(!filename.isNull()) {
731 // open destination file and initialize download
732 DownloadResource res;
733 res.file = new QFile(filename);
734 if(res.file->open(QFile::WriteOnly) == true) {
735 res.dialog = new QProgressDialog(tr("Downloading: ") + res.file->fileName(),
736 tr("Abort Download"), 0, 100, this);
737 connect(res.dialog, SIGNAL(canceled()), this, SLOT(abortDownload()));
738 download(mediaObject->currentSource().url(), res);
740 QMessageBox::critical(this, tr("File creation failed"), res.file->errorString());
746 void MainWindow::download(const QUrl& url, const DownloadResource& res) {
747 // create and store request and connect the reply signals
748 QNetworkReply *r = The::networkAccessManager()->get(QNetworkRequest(url));
749 m_downloads.insert(r, res);
750 connect(r, SIGNAL(finished()), this, SLOT(replyFinished()));
751 connect(r, SIGNAL(readyRead()), this, SLOT(replyReadyRead()));
752 connect(r, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(replyError(QNetworkReply::NetworkError)));
753 connect(r, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(replyDownloadProgress(qint64,qint64)));
754 connect(r, SIGNAL(metaDataChanged()), this, SLOT(replyMetaDataChanged()));
757 void MainWindow::replyReadyRead() {
758 QNetworkReply* r = dynamic_cast<QNetworkReply*>(this->sender());
759 m_downloads[r].file->write(r->readAll());
762 void MainWindow::replyDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) {
763 QNetworkReply* r = dynamic_cast<QNetworkReply*>(this->sender());
764 if (bytesTotal > 0 && bytesReceived >0)
765 m_downloads[r].dialog->setValue( double(100.0/bytesTotal)*bytesReceived ); // pssst :-X
768 void MainWindow::replyError(QNetworkReply::NetworkError code) {
769 QNetworkReply* r = dynamic_cast<QNetworkReply*>(this->sender());
770 QMessageBox::critical(this, tr("Download failed"), r->errorString());
773 void MainWindow::replyFinished() {
774 QNetworkReply* r = dynamic_cast<QNetworkReply*>(this->sender());
775 m_downloads[r].dialog->close();
776 m_downloads[r].file->close();
777 delete m_downloads[r].file;
778 m_downloads.remove(r);
781 void MainWindow::replyMetaDataChanged() {
782 QNetworkReply* r = dynamic_cast<QNetworkReply*>(this->sender());
783 QUrl url = r->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
785 // redirect - request new url, but keep the resources
786 qDebug() << "redirecting to: " << url.toString();
787 download(url, m_downloads[r]);
788 m_downloads.remove(r);
795 QPixmap MainWindow::createHDPixmap(bool enabled) {
796 QPixmap pixmap = QPixmap(24,24);
797 pixmap.fill(Qt::transparent);
798 QPainter painter(&pixmap);
799 painter.setRenderHints(QPainter::Antialiasing, true);
801 QRect rect(0, 3, 24, 18);
804 pen.setColor(Qt::black);
809 painter.setBrush(palette.highlight());
811 QLinearGradient gradient(QPointF(0, 0), QPointF(0, rect.height() / 2));
812 gradient.setColorAt(0, QColor(0x6d, 0x6d, 0x6d));
813 gradient.setColorAt(1, QColor(0x25, 0x25, 0x25));
814 painter.setBrush(QBrush(gradient));
816 painter.drawRoundedRect(rect, 5, 5);
819 pen.setColor(Qt::white);
822 pen.setColor(palette.highlightedText().color());
827 font.setPixelSize(12);
829 painter.setFont(font);
830 painter.drawText(rect, Qt::AlignCenter, "HD");
835 static QIcon hdOnIcon;
836 static QIcon hdOffIcon;
838 QIcon MainWindow::createHDIcon() {
840 hdOffIcon.addPixmap(createHDPixmap(false));
841 hdOnIcon.addPixmap(createHDPixmap(true));
845 void MainWindow::saveHdSetting(bool enabled) {
847 settings.setValue("hd", enabled);
848 QAction *hdAct = The::globalActions()->value("hd");
850 hdAct->setStatusTip(tr("High Definition video is enabled") + " (" + hdAct->shortcut().toString(QKeySequence::NativeText) + ")");
852 hdAct->setStatusTip(tr("High Definition video is not enabled") + " (" + hdAct->shortcut().toString(QKeySequence::NativeText) + ")");
856 void MainWindow::hdIndicator(bool isHd) {
857 QAction *hdAct = The::globalActions()->value("hd");
859 hdAct->setIcon(hdOnIcon);
860 hdAct->setToolTip(tr("The current video is in High Definition"));
862 hdAct->setIcon(hdOffIcon);
863 hdAct->setToolTip(tr("The current video is not in High Definition"));