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);
53 MainWindow::~MainWindow() {
57 void MainWindow::createActions() {
59 QMap<QString, QAction*> *actions = The::globalActions();
62 settingsAct = new QAction(tr("&Preferences..."), this);
63 settingsAct->setStatusTip(tr(QString("Configure ").append(Constants::APP_NAME).toUtf8()));
65 settingsAct->setMenuRole(QAction::PreferencesRole);
66 actions->insert("settings", settingsAct);
67 connect(settingsAct, SIGNAL(triggered()), this, SLOT(showSettings()));
70 backAct = new QAction(QIcon(":/images/go-previous.png"), tr("&Back"), this);
71 backAct->setEnabled(false);
72 backAct->setShortcut(QKeySequence(Qt::ALT + Qt::Key_Left));
73 backAct->setStatusTip(tr("Go to the previous view"));
74 actions->insert("back", backAct);
75 connect(backAct, SIGNAL(triggered()), this, SLOT(goBack()));
77 stopAct = new QAction(QtIconLoader::icon("media-stop", QIcon(":/images/stop.png")), tr("&Stop"), this);
78 stopAct->setStatusTip(tr("Stop playback and go back to the search view"));
79 stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
80 actions->insert("stop", stopAct);
81 connect(stopAct, SIGNAL(triggered()), this, SLOT(stop()));
83 skipAct = new QAction(QtIconLoader::icon("media-skip-forward", QIcon(":/images/skip.png")), tr("S&kip"), this);
84 skipAct->setStatusTip(tr("Skip to the next video"));
85 skipAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_Right) << QKeySequence(Qt::Key_MediaNext));
86 skipAct->setEnabled(false);
87 actions->insert("skip", skipAct);
88 connect(skipAct, SIGNAL(triggered()), mediaView, SLOT(skip()));
90 pauseAct = new QAction(QtIconLoader::icon("media-pause", QIcon(":/images/pause.png")), tr("&Pause"), this);
91 pauseAct->setStatusTip(tr("Pause playback"));
92 pauseAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Space) << QKeySequence(Qt::Key_MediaPlay));
93 pauseAct->setEnabled(false);
94 actions->insert("pause", pauseAct);
95 connect(pauseAct, SIGNAL(triggered()), mediaView, SLOT(pause()));
97 fullscreenAct = new QAction(QtIconLoader::icon("view-fullscreen", QIcon(":/images/view-fullscreen.png")), tr("&Full Screen"), this);
98 fullscreenAct->setStatusTip(tr("Go full screen"));
99 fullscreenAct->setShortcut(QKeySequence(Qt::ALT + Qt::Key_Return));
100 fullscreenAct->setShortcutContext(Qt::ApplicationShortcut);
101 actions->insert("fullscreen", fullscreenAct);
102 connect(fullscreenAct, SIGNAL(triggered()), this, SLOT(fullscreen()));
104 compactViewAct = new QAction(tr("&Compact mode"), this);
105 compactViewAct->setStatusTip(tr("Hide the playlist and the toolbar"));
106 compactViewAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Return));
107 compactViewAct->setCheckable(true);
108 compactViewAct->setChecked(false);
109 compactViewAct->setEnabled(false);
110 actions->insert("compactView", compactViewAct);
111 connect(compactViewAct, SIGNAL(toggled(bool)), this, SLOT(compactView(bool)));
114 // icon should be document-save but it is ugly
115 downloadAct = new QAction(QtIconLoader::icon("go-down", QIcon(":/images/go-down.png")), tr("&Download"), this);
116 downloadAct->setStatusTip(tr("Download this video"));
117 downloadAct->setShortcut(tr("Ctrl+S"));
118 downloadAct->setEnabled(false);
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 removeAct->setShortcuts(QList<QKeySequence>() << QKeySequence("Del") << QKeySequence("Backspace"));
133 removeAct->setEnabled(false);
134 actions->insert("remove", removeAct);
135 connect(removeAct, SIGNAL(triggered()), mediaView, SLOT(removeSelected()));
137 moveUpAct = new QAction(QtIconLoader::icon("go-up", QIcon(":/images/go-up.png")), tr("Move &Up"), this);
138 moveUpAct->setStatusTip(tr("Move up the selected videos in the playlist"));
139 moveUpAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Up));
140 moveUpAct->setEnabled(false);
141 actions->insert("moveUp", moveUpAct);
142 connect(moveUpAct, SIGNAL(triggered()), mediaView, SLOT(moveUpSelected()));
144 moveDownAct = new QAction(QtIconLoader::icon("go-down", QIcon(":/images/go-down.png")), tr("Move &Down"), this);
145 moveDownAct->setStatusTip(tr("Move down the selected videos in the playlist"));
146 moveDownAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Down));
147 moveDownAct->setEnabled(false);
148 actions->insert("moveDown", moveDownAct);
149 connect(moveDownAct, SIGNAL(triggered()), mediaView, SLOT(moveDownSelected()));
151 quitAct = new QAction(tr("&Quit"), this);
152 quitAct->setMenuRole(QAction::QuitRole);
153 quitAct->setShortcut(tr("Ctrl+Q"));
154 quitAct->setStatusTip(tr("Bye"));
155 actions->insert("quit", quitAct);
156 connect(quitAct, SIGNAL(triggered()), this, SLOT(quit()));
158 siteAct = new QAction(tr("&Website"), this);
159 siteAct->setShortcut(QKeySequence::HelpContents);
160 siteAct->setStatusTip(tr("%1 on the Web").arg(Constants::APP_NAME));
161 actions->insert("site", siteAct);
162 connect(siteAct, SIGNAL(triggered()), this, SLOT(visitSite()));
164 donateAct = new QAction(tr("&Donate via PayPal"), this);
165 donateAct->setStatusTip(tr("Please support the continued development of %1").arg(Constants::APP_NAME));
166 actions->insert("donate", donateAct);
167 connect(donateAct, SIGNAL(triggered()), this, SLOT(donate()));
169 aboutAct = new QAction(tr("&About"), this);
170 aboutAct->setMenuRole(QAction::AboutRole);
171 aboutAct->setStatusTip(tr("Info about %1").arg(Constants::APP_NAME));
172 actions->insert("about", aboutAct);
173 connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
177 searchFocusAct = new QAction(this);
178 searchFocusAct->setShortcut(QKeySequence::Find);
179 actions->insert("search", searchFocusAct);
180 connect(searchFocusAct, SIGNAL(triggered()), this, SLOT(searchFocus()));
181 addAction(searchFocusAct);
183 volumeUpAct = new QAction(this);
184 volumeUpAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Plus));
185 actions->insert("volume-up", volumeUpAct);
186 connect(volumeUpAct, SIGNAL(triggered()), this, SLOT(volumeUp()));
187 addAction(volumeUpAct);
189 volumeDownAct = new QAction(this);
190 volumeDownAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Minus));
191 actions->insert("volume-down", volumeDownAct);
192 connect(volumeDownAct, SIGNAL(triggered()), this, SLOT(volumeDown()));
193 addAction(volumeDownAct);
195 volumeMuteAct = new QAction(this);
196 volumeMuteAct->setShortcut(tr("Ctrl+M"));
197 actions->insert("volume-mute", volumeMuteAct);
198 connect(volumeMuteAct, SIGNAL(triggered()), this, SLOT(volumeMute()));
199 addAction(volumeMuteAct);
201 // common action properties
202 foreach (QAction *action, actions->values()) {
204 // add actions to the MainWindow so that they work
205 // when the menu is hidden
209 // unexperienced users tend to keep keys pressed for a "long" time
210 action->setAutoRepeat(false);
211 action->setToolTip(action->statusTip());
213 // show keyboard shortcuts in the status bar
214 if (!action->shortcut().isEmpty())
215 action->setStatusTip(action->statusTip() + " (" + action->shortcut().toString() + ")");
217 // make the actions work when video is fullscreen
218 action->setShortcutContext(Qt::ApplicationShortcut);
221 // OSX does not use icons in menus
222 action->setIconVisibleInMenu(false);
229 void MainWindow::createMenus() {
231 QMap<QString, QMenu*> *menus = The::globalMenus();
233 fileMenu = menuBar()->addMenu(tr("&Application"));
234 // menus->insert("file", fileMenu);
235 // fileMenu->addAction(settingsAct);
236 fileMenu->addSeparator();
237 fileMenu->addAction(quitAct);
239 playlistMenu = menuBar()->addMenu(tr("&Playlist"));
240 menus->insert("playlist", playlistMenu);
241 playlistMenu->addAction(removeAct);
242 playlistMenu->addSeparator();
243 playlistMenu->addAction(moveUpAct);
244 playlistMenu->addAction(moveDownAct);
246 viewMenu = menuBar()->addMenu(tr("&Video"));
247 menus->insert("video", viewMenu);
248 // viewMenu->addAction(backAct);
249 viewMenu->addAction(stopAct);
250 viewMenu->addAction(pauseAct);
251 viewMenu->addAction(skipAct);
252 viewMenu->addSeparator();
253 viewMenu->addAction(webPageAct);
254 viewMenu->addSeparator();
255 // viewMenu->addAction(downloadAct);
256 viewMenu->addAction(compactViewAct);
257 viewMenu->addAction(fullscreenAct);
259 helpMenu = menuBar()->addMenu(tr("&Help"));
260 helpMenu->addAction(siteAct);
261 helpMenu->addAction(donateAct);
262 helpMenu->addAction(aboutAct);
265 void MainWindow::createToolBars() {
267 setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
269 mainToolBar = new QToolBar(this);
270 mainToolBar->setFloatable(false);
271 mainToolBar->setMovable(false);
274 smallerFont.setPointSize(smallerFont.pointSize()*.85);
275 mainToolBar->setFont(smallerFont);
277 mainToolBar->setIconSize(QSize(32,32));
278 // mainToolBar->addAction(backAct);
279 mainToolBar->addAction(stopAct);
280 mainToolBar->addAction(pauseAct);
281 mainToolBar->addAction(skipAct);
282 mainToolBar->addAction(fullscreenAct);
284 seekSlider = new Phonon::SeekSlider(this);
285 seekSlider->setIconVisible(false);
286 Spacer *seekSliderSpacer = new Spacer(mainToolBar, seekSlider);
287 seekSliderSpacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
288 mainToolBar->addWidget(seekSliderSpacer);
290 volumeSlider = new Phonon::VolumeSlider(this);
291 // this makes the volume slider smaller
292 volumeSlider->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
293 mainToolBar->addWidget(new Spacer(mainToolBar, volumeSlider));
295 mainToolBar->addWidget(new Spacer(mainToolBar, toolbarSearch));
297 addToolBar(mainToolBar);
300 void MainWindow::createStatusBar() {
301 currentTime = new QLabel(this);
302 statusBar()->addPermanentWidget(currentTime);
304 totalTime = new QLabel(this);
305 statusBar()->addPermanentWidget(totalTime);
307 // remove ugly borders on OSX
308 statusBar()->setStyleSheet("::item{border:0 solid}");
313 void MainWindow::readSettings() {
315 restoreGeometry(settings.value("geometry").toByteArray());
318 void MainWindow::writeSettings() {
319 // do not save geometry when in full screen
323 settings.setValue("geometry", saveGeometry());
326 void MainWindow::goBack() {
327 if ( history->size() > 1 ) {
329 QWidget *widget = history->pop();
334 void MainWindow::showWidget ( QWidget* widget ) {
336 setUpdatesEnabled(false);
338 // call hide method on the current view
339 View* oldView = dynamic_cast<View *> (views->currentWidget());
340 if (oldView != NULL) {
341 oldView->disappear();
344 // call show method on the new view
345 View* newView = dynamic_cast<View *> (widget);
346 if (newView != NULL) {
348 QMap<QString,QVariant> metadata = newView->metadata();
349 QString windowTitle = metadata.value("title").toString();
350 if (windowTitle.length())
351 windowTitle += " - ";
352 setWindowTitle(windowTitle + Constants::APP_NAME);
353 statusBar()->showMessage((metadata.value("description").toString()));
357 // backAct->setEnabled(history->size() > 1);
358 // settingsAct->setEnabled(widget != settingsView);
359 stopAct->setEnabled(widget == mediaView);
360 fullscreenAct->setEnabled(widget == mediaView);
361 compactViewAct->setEnabled(widget == mediaView);
362 webPageAct->setEnabled(widget == mediaView);
363 aboutAct->setEnabled(widget != aboutView);
366 // this is not the best place to enable downloads, but the user is informed
367 // if there really is no video is playing
368 downloadAct->setEnabled(widget == mediaView);
371 // cool toolbar on the Mac
372 // setUnifiedTitleAndToolBarOnMac(widget == mediaView);
374 // toolbar only for the mediaView
375 mainToolBar->setVisible(widget == mediaView && !compactViewAct->isChecked());
377 history->push(widget);
380 // crossfade only on OSX
381 // where we can be sure of video performance
382 fadeInWidget(views->currentWidget(), widget);
385 views->setCurrentWidget(widget);
387 setUpdatesEnabled(true);
390 void MainWindow::fadeInWidget(QWidget *oldWidget, QWidget *newWidget) {
391 if (faderWidget) faderWidget->close();
392 if (!oldWidget || !newWidget || oldWidget == mediaView || newWidget == mediaView) return;
393 QPixmap frozenView = QPixmap::grabWidget(oldWidget);
394 faderWidget = new FaderWidget(newWidget);
395 faderWidget->start(frozenView);
398 void MainWindow::about() {
400 aboutView = new AboutView(this);
401 views->addWidget(aboutView);
403 showWidget(aboutView);
406 void MainWindow::visitSite() {
407 QUrl url(Constants::WEBSITE);
408 statusBar()->showMessage(QString(tr("Opening %1").arg(url.toString())));
409 QDesktopServices::openUrl(url);
412 void MainWindow::donate() {
413 QUrl url(QString(Constants::WEBSITE) + "#donate");
414 statusBar()->showMessage(QString(tr("Opening %1").arg(url.toString())));
415 QDesktopServices::openUrl(url);
418 void MainWindow::quit() {
423 void MainWindow::closeEvent(QCloseEvent *event) {
425 QWidget::closeEvent(event);
428 void MainWindow::showSettings() {
430 settingsView = new SettingsView(this);
431 views->addWidget(settingsView);
433 showWidget(settingsView);
436 void MainWindow::showSearch() {
437 showWidget(searchView);
438 currentTime->clear();
442 void MainWindow::showMedia(QString query) {
444 mediaView->setMediaObject(mediaObject);
445 SearchParams *searchParams = new SearchParams();
446 searchParams->setKeywords(query);
447 mediaView->search(searchParams);
448 showWidget(mediaView);
451 void MainWindow::stateChanged(Phonon::State newState, Phonon::State /* oldState */) {
453 // qDebug() << "Phonon state: " << newState;
457 case Phonon::ErrorState:
458 if (mediaObject->errorType() == Phonon::FatalError) {
459 statusBar()->showMessage(tr("Fatal error: %1").arg(mediaObject->errorString()));
461 statusBar()->showMessage(tr("Error: %1").arg(mediaObject->errorString()));
465 case Phonon::PlayingState:
466 pauseAct->setEnabled(true);
467 pauseAct->setIcon(QtIconLoader::icon("media-pause", QIcon(":/images/pause.png")));
468 pauseAct->setText(tr("&Pause"));
469 pauseAct->setStatusTip(tr("Pause playback"));
470 skipAct->setEnabled(true);
473 case Phonon::StoppedState:
474 pauseAct->setEnabled(false);
475 skipAct->setEnabled(false);
478 case Phonon::PausedState:
479 skipAct->setEnabled(true);
480 pauseAct->setEnabled(true);
481 pauseAct->setIcon(QtIconLoader::icon("media-play", QIcon(":/images/play.png")));
482 pauseAct->setText(tr("&Play"));
483 pauseAct->setStatusTip(tr("Resume playback"));
486 case Phonon::BufferingState:
487 case Phonon::LoadingState:
488 skipAct->setEnabled(true);
489 pauseAct->setEnabled(false);
490 currentTime->clear();
499 void MainWindow::stop() {
504 void MainWindow::fullscreen() {
506 setUpdatesEnabled(false);
509 // use setShortucs instead of setShortcut
510 // the latter seems not to work
511 fullscreenAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::ALT + Qt::Key_Return));
512 fullscreenAct->setText(tr("&Full Screen"));
513 stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::Key_MediaStop));
514 if (m_maximized) showMaximized();
517 stopAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_MediaStop));
518 fullscreenAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::ALT + Qt::Key_Return));
519 fullscreenAct->setText(tr("Exit &Full Screen"));
520 m_maximized = isMaximized();
522 // save geometry now, if the user quits when in full screen
523 // geometry won't be saved
529 // No compact view action when in full screen
530 compactViewAct->setVisible(m_fullscreen);
531 // Also no Youtube action since it opens a new window
532 webPageAct->setVisible(m_fullscreen);
534 // Hide anything but the video
535 mediaView->setPlaylistVisible(m_fullscreen);
536 mainToolBar->setVisible(m_fullscreen);
537 statusBar()->setVisible(m_fullscreen);
538 menuBar()->setVisible(m_fullscreen);
540 m_fullscreen = !m_fullscreen;
542 setUpdatesEnabled(true);
545 void MainWindow::compactView(bool enable) {
547 setUpdatesEnabled(false);
549 // setUnifiedTitleAndToolBarOnMac(!enable);
550 mediaView->setPlaylistVisible(!enable);
551 mainToolBar->setVisible(!enable);
552 statusBar()->setVisible(!enable);
554 // ensure focus does not end up to the search box
555 // as it would steal the Space shortcut
556 toolbarSearch->setEnabled(!enable);
559 stopAct->setShortcut(QString(""));
560 QList<QKeySequence> shortcuts;
561 // for some reason it is important that ESC comes first
562 shortcuts << QKeySequence(Qt::CTRL + Qt::Key_Return) << QKeySequence(Qt::Key_Escape);
563 compactViewAct->setShortcuts(shortcuts);
565 compactViewAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Return));
566 stopAct->setShortcut(QKeySequence(Qt::Key_Escape));
569 setUpdatesEnabled(true);
572 void MainWindow::searchFocus() {
573 QWidget *view = views->currentWidget();
574 if (view == mediaView) {
575 toolbarSearch->setFocus();
579 void MainWindow::initPhonon() {
580 // Phonon initialization
581 if (mediaObject) delete mediaObject;
582 if (audioOutput) delete audioOutput;
583 mediaObject = new Phonon::MediaObject(this);
584 mediaObject->setTickInterval(100);
585 connect(mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
586 this, SLOT(stateChanged(Phonon::State, Phonon::State)));
587 connect(mediaObject, SIGNAL(tick(qint64)), this, SLOT(tick(qint64)));
588 connect(mediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64)));
589 seekSlider->setMediaObject(mediaObject);
590 audioOutput = new Phonon::AudioOutput(Phonon::VideoCategory, this);
591 connect(audioOutput, SIGNAL(volumeChanged(qreal)), this, SLOT(volumeChanged(qreal)));
592 connect(audioOutput, SIGNAL(mutedChanged(bool)), this, SLOT(volumeMutedChanged(bool)));
593 volumeSlider->setAudioOutput(audioOutput);
594 Phonon::createPath(mediaObject, audioOutput);
597 void MainWindow::tick(qint64 time) {
599 currentTime->clear();
602 QTime displayTime(0, (time / 60000) % 60, (time / 1000) % 60);
603 currentTime->setText(displayTime.toString("mm:ss"));
604 // qDebug() << "currentTime" << time << displayTime.toString("mm:ss");
607 void MainWindow::totalTimeChanged(qint64 time) {
612 QTime displayTime(0, (time / 60000) % 60, (time / 1000) % 60);
613 totalTime->setText(displayTime.toString("/ mm:ss"));
614 // qDebug() << "totalTime" << time << displayTime.toString("mm:ss");
617 void MainWindow::volumeUp() {
618 qreal newVolume = volumeSlider->audioOutput()->volume() + .1;
619 if (newVolume > volumeSlider->maximumVolume())
620 newVolume = volumeSlider->maximumVolume();
621 volumeSlider->audioOutput()->setVolume(newVolume);
624 void MainWindow::volumeDown() {
625 qreal newVolume = volumeSlider->audioOutput()->volume() - .1;
628 volumeSlider->audioOutput()->setVolume(newVolume);
631 void MainWindow::volumeMute() {
632 volumeSlider->audioOutput()->setMuted(!volumeSlider->audioOutput()->isMuted());
635 void MainWindow::volumeChanged(qreal newVolume) {
636 // automatically unmute when volume changes
637 if (volumeSlider->audioOutput()->isMuted())
638 volumeSlider->audioOutput()->setMuted(false);
639 statusBar()->showMessage(tr("Volume at %1%").arg(newVolume*100));
642 void MainWindow::volumeMutedChanged(bool muted) {
644 statusBar()->showMessage(tr("Volume is muted"));
646 statusBar()->showMessage(tr("Volume is unmuted"));
650 void MainWindow::abortDownload() {
651 QProgressDialog* dlg = dynamic_cast<QProgressDialog*>(this->sender());
652 QMap<QNetworkReply*, DownloadResource>::iterator cur;
653 QMap<QNetworkReply*, DownloadResource>::iterator end;
654 // locate the DownloadResource by its dialog address and trigger abortion
655 for(cur=m_downloads.begin(), end=m_downloads.end(); cur!=end; cur++){
656 if(cur.value().dialog == dlg) cur.key()->abort();
660 void MainWindow::download() {
661 if(mediaObject == NULL || mediaObject->currentSource().url().isEmpty()){
662 // complain unless video source apperas to be valid
663 QMessageBox::critical(this, tr("No Video playing"), tr("You must first play the video you intent to download !"));
666 QString filename = QFileDialog::getSaveFileName(this,
667 tr("Save video as..."),
668 tr("minitube video.mp4"),
669 "Video File(*.avi *.mp4)"
671 if(!filename.isNull()) {
672 // open destination file and initialize download
673 DownloadResource res;
674 res.file = new QFile(filename);
675 if(res.file->open(QFile::WriteOnly) == true) {
676 res.dialog = new QProgressDialog(tr("Downloading: ") + res.file->fileName(),
677 tr("Abort Download"), 0, 100, this);
678 connect(res.dialog, SIGNAL(canceled()), this, SLOT(abortDownload()));
679 download(mediaObject->currentSource().url(), res);
681 QMessageBox::critical(this, tr("File creation failed"), res.file->errorString());
687 void MainWindow::download(const QUrl& url, const DownloadResource& res) {
688 // create and store request and connect the reply signals
689 QNetworkReply *r = The::networkAccessManager()->get(QNetworkRequest(url));
690 m_downloads.insert(r, res);
691 connect(r, SIGNAL(finished()), this, SLOT(replyFinished()));
692 connect(r, SIGNAL(readyRead()), this, SLOT(replyReadyRead()));
693 connect(r, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(replyError(QNetworkReply::NetworkError)));
694 connect(r, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(replyDownloadProgress(qint64,qint64)));
695 connect(r, SIGNAL(metaDataChanged()), this, SLOT(replyMetaDataChanged()));
698 void MainWindow::replyReadyRead() {
699 QNetworkReply* r = dynamic_cast<QNetworkReply*>(this->sender());
700 m_downloads[r].file->write(r->readAll());
703 void MainWindow::replyDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) {
704 QNetworkReply* r = dynamic_cast<QNetworkReply*>(this->sender());
705 if (bytesTotal > 0 && bytesReceived >0)
706 m_downloads[r].dialog->setValue( double(100.0/bytesTotal)*bytesReceived ); // pssst :-X
709 void MainWindow::replyError(QNetworkReply::NetworkError code) {
710 QNetworkReply* r = dynamic_cast<QNetworkReply*>(this->sender());
711 QMessageBox::critical(this, tr("Download failed"), r->errorString());
714 void MainWindow::replyFinished() {
715 QNetworkReply* r = dynamic_cast<QNetworkReply*>(this->sender());
716 m_downloads[r].dialog->close();
717 m_downloads[r].file->close();
718 delete m_downloads[r].file;
719 m_downloads.remove(r);
722 void MainWindow::replyMetaDataChanged() {
723 QNetworkReply* r = dynamic_cast<QNetworkReply*>(this->sender());
724 QUrl url = r->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
726 // redirect - request new url, but keep the resources
727 qDebug() << "redirecting to: " << url.toString();
728 download(url, m_downloads[r]);
729 m_downloads.remove(r);