1 #include "MainWindow.h"
4 #include "iconloader/qticonloader.h"
7 MainWindow::MainWindow() {
13 history = new QStack<QWidget*>();
14 views = new QStackedWidget(this);
17 searchView = new SearchView(this);
18 connect(searchView, SIGNAL(search(QString)), this, SLOT(showMedia(QString)));
19 views->addWidget(searchView);
20 mediaView = new MediaView(this);
21 views->addWidget(mediaView);
23 // lazily initialized views
27 toolbarSearch = new SearchLineEdit(this);
28 toolbarSearch->setFont(qApp->font());
29 connect(toolbarSearch, SIGNAL(search(const QString&)), searchView, SLOT(watch(const QString&)));
37 // remove that useless menu/toolbar context menu
38 this->setContextMenuPolicy(Qt::NoContextMenu);
40 // mediaView init stuff thats needs actions
41 mediaView->initialize();
43 // restore window position
46 // show the initial view
47 showWidget(searchView);
49 setCentralWidget(views);
52 MainWindow::~MainWindow() {
56 void MainWindow::createActions() {
58 QMap<QString, QAction*> *actions = The::globalActions();
61 settingsAct = new QAction(tr("&Preferences..."), this);
62 settingsAct->setStatusTip(tr(QString("Configure ").append(Constants::APP_NAME).toUtf8()));
64 settingsAct->setMenuRole(QAction::PreferencesRole);
65 actions->insert("settings", settingsAct);
66 connect(settingsAct, SIGNAL(triggered()), this, SLOT(showSettings()));
69 backAct = new QAction(QIcon(":/images/go-previous.png"), tr("&Back"), this);
70 backAct->setEnabled(false);
71 backAct->setShortcut(QKeySequence(Qt::ALT + Qt::Key_Left));
72 backAct->setStatusTip(tr("Go to the previous view"));
73 actions->insert("back", backAct);
74 connect(backAct, SIGNAL(triggered()), this, SLOT(goBack()));
76 stopAct = new QAction(QtIconLoader::icon("media-stop", QIcon(":/images/stop.png")), tr("&Stop"), this);
77 stopAct->setStatusTip(tr("Stop playback and go back to the search view"));
78 stopAct->setShortcut(QKeySequence(Qt::Key_Escape));
79 actions->insert("stop", stopAct);
80 connect(stopAct, SIGNAL(triggered()), this, SLOT(stop()));
82 skipAct = new QAction(QtIconLoader::icon("media-skip-forward", QIcon(":/images/skip.png")), tr("S&kip"), this);
83 skipAct->setStatusTip(tr("Skip to the next video"));
84 skipAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Right));
85 skipAct->setEnabled(false);
86 actions->insert("skip", skipAct);
87 connect(skipAct, SIGNAL(triggered()), mediaView, SLOT(skip()));
89 pauseAct = new QAction(QtIconLoader::icon("media-pause", QIcon(":/images/pause.png")), tr("&Pause"), this);
90 pauseAct->setStatusTip(tr("Pause playback"));
91 pauseAct->setShortcut(QKeySequence(Qt::Key_Space));
92 pauseAct->setEnabled(false);
93 actions->insert("pause", pauseAct);
94 connect(pauseAct, SIGNAL(triggered()), mediaView, SLOT(pause()));
96 fullscreenAct = new QAction(QtIconLoader::icon("view-fullscreen", QIcon(":/images/view-fullscreen.png")), tr("&Full Screen"), this);
97 fullscreenAct->setStatusTip(tr("Go full screen"));
98 fullscreenAct->setShortcut(QKeySequence(Qt::ALT + Qt::Key_Return));
99 fullscreenAct->setShortcutContext(Qt::ApplicationShortcut);
100 actions->insert("fullscreen", fullscreenAct);
101 connect(fullscreenAct, SIGNAL(triggered()), this, SLOT(fullscreen()));
103 compactViewAct = new QAction(tr("&Compact mode"), this);
104 compactViewAct->setStatusTip(tr("Hide the playlist and the toolbar"));
105 compactViewAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Return));
106 compactViewAct->setCheckable(true);
107 compactViewAct->setChecked(false);
108 compactViewAct->setEnabled(false);
109 actions->insert("compactView", compactViewAct);
110 connect(compactViewAct, SIGNAL(toggled(bool)), this, SLOT(compactView(bool)));
113 // icon should be document-save but it is ugly
114 downloadAct = new QAction(QtIconLoader::icon("go-down", QIcon(":/images/go-down.png")), tr("&Download"), this);
115 downloadAct->setStatusTip(tr("Download this video"));
116 downloadAct->setShortcut(tr("Ctrl+S"));
117 downloadAct->setEnabled(false);
118 actions->insert("download", downloadAct);
119 connect(downloadAct, SIGNAL(triggered()), this, SLOT(download()));
122 webPageAct = new QAction(QtIconLoader::icon("internet-web-browser", QIcon(":/images/internet-web-browser.png")), tr("&YouTube"), this);
123 webPageAct->setStatusTip(tr("Open the YouTube video page"));
124 webPageAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Y));
125 webPageAct->setEnabled(false);
126 actions->insert("webpage", webPageAct);
127 connect(webPageAct, SIGNAL(triggered()), mediaView, SLOT(openWebPage()));
129 removeAct = new QAction(tr("&Remove"), this);
130 removeAct->setStatusTip(tr("Remove the selected videos from the playlist"));
131 QList<QKeySequence> shortcuts;
132 shortcuts << QKeySequence("Del") << QKeySequence("Backspace");
133 removeAct->setShortcuts(shortcuts);
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->setShortcut(tr("Ctrl+Q"));
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 actions->insert("search", searchFocusAct);
181 connect(searchFocusAct, SIGNAL(triggered()), this, SLOT(searchFocus()));
182 addAction(searchFocusAct);
184 volumeUpAct = new QAction(this);
185 volumeUpAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Plus));
186 actions->insert("volume-up", volumeUpAct);
187 connect(volumeUpAct, SIGNAL(triggered()), this, SLOT(volumeUp()));
188 addAction(volumeUpAct);
190 volumeDownAct = new QAction(this);
191 volumeDownAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Minus));
192 actions->insert("volume-down", volumeDownAct);
193 connect(volumeDownAct, SIGNAL(triggered()), this, SLOT(volumeDown()));
194 addAction(volumeDownAct);
196 volumeMuteAct = new QAction(this);
197 volumeMuteAct->setShortcut(tr("Ctrl+M"));
198 actions->insert("volume-mute", volumeMuteAct);
199 connect(volumeMuteAct, SIGNAL(triggered()), this, SLOT(volumeMute()));
200 addAction(volumeMuteAct);
202 // common action properties
203 foreach (QAction *action, actions->values()) {
205 // add actions to the MainWindow so that they work
206 // when the menu is hidden
210 // unexperienced users tend to keep keys pressed for a "long" time
211 action->setAutoRepeat(false);
212 action->setToolTip(action->statusTip());
214 // make the actions work when video is fullscreen
215 action->setShortcutContext(Qt::ApplicationShortcut);
218 // OSX does not use icons in menus
219 action->setIconVisibleInMenu(false);
226 void MainWindow::createMenus() {
228 QMap<QString, QMenu*> *menus = The::globalMenus();
230 fileMenu = menuBar()->addMenu(tr("&Application"));
231 // menus->insert("file", fileMenu);
232 // fileMenu->addAction(settingsAct);
233 fileMenu->addSeparator();
234 fileMenu->addAction(quitAct);
236 playlistMenu = menuBar()->addMenu(tr("&Playlist"));
237 menus->insert("playlist", playlistMenu);
238 playlistMenu->addAction(removeAct);
239 playlistMenu->addSeparator();
240 playlistMenu->addAction(moveUpAct);
241 playlistMenu->addAction(moveDownAct);
243 viewMenu = menuBar()->addMenu(tr("&Video"));
244 menus->insert("video", viewMenu);
245 // viewMenu->addAction(backAct);
246 viewMenu->addAction(stopAct);
247 viewMenu->addAction(pauseAct);
248 viewMenu->addAction(skipAct);
249 viewMenu->addSeparator();
250 viewMenu->addAction(webPageAct);
251 viewMenu->addSeparator();
252 // viewMenu->addAction(downloadAct);
253 viewMenu->addAction(compactViewAct);
254 viewMenu->addAction(fullscreenAct);
256 helpMenu = menuBar()->addMenu(tr("&Help"));
257 helpMenu->addAction(siteAct);
258 helpMenu->addAction(donateAct);
259 helpMenu->addAction(aboutAct);
262 void MainWindow::createToolBars() {
264 setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
266 mainToolBar = new QToolBar(this);
267 mainToolBar->setFloatable(false);
268 mainToolBar->setMovable(false);
271 smallerFont.setPointSize(smallerFont.pointSize()*.85);
272 mainToolBar->setFont(smallerFont);
274 mainToolBar->setIconSize(QSize(32,32));
275 // mainToolBar->addAction(backAct);
276 mainToolBar->addAction(stopAct);
277 mainToolBar->addAction(pauseAct);
278 mainToolBar->addAction(skipAct);
279 mainToolBar->addAction(fullscreenAct);
281 seekSlider = new Phonon::SeekSlider(this);
282 seekSlider->setIconVisible(false);
283 Spacer *seekSliderSpacer = new Spacer(mainToolBar, seekSlider);
284 seekSliderSpacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
285 mainToolBar->addWidget(seekSliderSpacer);
287 volumeSlider = new Phonon::VolumeSlider(this);
288 // this makes the volume slider smaller
289 volumeSlider->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
290 mainToolBar->addWidget(new Spacer(mainToolBar, volumeSlider));
292 mainToolBar->addWidget(new Spacer(mainToolBar, toolbarSearch));
294 addToolBar(mainToolBar);
297 void MainWindow::createStatusBar() {
298 currentTime = new QLabel(this);
299 statusBar()->addPermanentWidget(currentTime);
301 totalTime = new QLabel(this);
302 statusBar()->addPermanentWidget(totalTime);
304 // remove ugly borders on OSX
305 statusBar()->setStyleSheet("::item{border:0 solid}");
310 void MainWindow::readSettings() {
312 restoreGeometry(settings.value("geometry").toByteArray());
315 void MainWindow::writeSettings() {
316 // do not save geometry when in full screen
320 settings.setValue("geometry", saveGeometry());
323 void MainWindow::goBack() {
324 if ( history->size() > 1 ) {
326 QWidget *widget = history->pop();
331 void MainWindow::showWidget ( QWidget* widget ) {
333 setUpdatesEnabled(false);
335 // call hide method on the current view
336 View* oldView = dynamic_cast<View *> (views->currentWidget());
337 if (oldView != NULL) {
338 oldView->disappear();
341 // call show method on the new view
342 View* newView = dynamic_cast<View *> (widget);
343 if (newView != NULL) {
345 QMap<QString,QVariant> metadata = newView->metadata();
346 QString windowTitle = metadata.value("title").toString();
347 if (windowTitle.length())
348 windowTitle += " - ";
349 setWindowTitle(windowTitle + Constants::APP_NAME);
350 statusBar()->showMessage((metadata.value("description").toString()));
354 // backAct->setEnabled(history->size() > 1);
355 // settingsAct->setEnabled(widget != settingsView);
356 stopAct->setEnabled(widget == mediaView);
357 fullscreenAct->setEnabled(widget == mediaView);
358 compactViewAct->setEnabled(widget == mediaView);
359 webPageAct->setEnabled(widget == mediaView);
360 aboutAct->setEnabled(widget != aboutView);
363 // this is not the best place to enable downloads, but the user is informed
364 // if there really is no video is playing
365 downloadAct->setEnabled(widget == mediaView);
368 // cool toolbar on the Mac
369 // setUnifiedTitleAndToolBarOnMac(widget == mediaView);
371 // toolbar only for the mediaView
372 mainToolBar->setVisible(widget == mediaView && !compactViewAct->isChecked());
374 history->push(widget);
377 // crossfade only on OSX
378 // where we can be sure of video performance
379 fadeInWidget(views->currentWidget(), widget);
382 views->setCurrentWidget(widget);
384 setUpdatesEnabled(true);
387 void MainWindow::fadeInWidget(QWidget *oldWidget, QWidget *newWidget) {
388 if (faderWidget) faderWidget->close();
389 if (!oldWidget || !newWidget || oldWidget == mediaView || newWidget == mediaView) return;
390 QPixmap frozenView = QPixmap::grabWidget(oldWidget);
391 faderWidget = new FaderWidget(newWidget);
392 faderWidget->start(frozenView);
395 void MainWindow::about() {
397 aboutView = new AboutView(this);
398 views->addWidget(aboutView);
400 showWidget(aboutView);
403 void MainWindow::visitSite() {
404 QUrl url(Constants::WEBSITE);
405 statusBar()->showMessage(QString(tr("Opening %1").arg(url.toString())));
406 QDesktopServices::openUrl(url);
409 void MainWindow::donate() {
410 QUrl url(QString(Constants::WEBSITE) + "#donate");
411 statusBar()->showMessage(QString(tr("Opening %1").arg(url.toString())));
412 QDesktopServices::openUrl(url);
415 void MainWindow::quit() {
420 void MainWindow::closeEvent(QCloseEvent *event) {
422 QWidget::closeEvent(event);
425 void MainWindow::showSettings() {
427 settingsView = new SettingsView(this);
428 views->addWidget(settingsView);
430 showWidget(settingsView);
433 void MainWindow::showSearch() {
434 showWidget(searchView);
435 currentTime->clear();
439 void MainWindow::showMedia(QString query) {
441 mediaView->setMediaObject(mediaObject);
442 SearchParams *searchParams = new SearchParams();
443 searchParams->setKeywords(query);
444 mediaView->search(searchParams);
445 showWidget(mediaView);
448 void MainWindow::stateChanged(Phonon::State newState, Phonon::State /* oldState */) {
450 // qDebug() << "Phonon state: " << newState;
454 case Phonon::ErrorState:
455 if (mediaObject->errorType() == Phonon::FatalError) {
456 statusBar()->showMessage(tr("Fatal error: %1").arg(mediaObject->errorString()));
458 statusBar()->showMessage(tr("Error: %1").arg(mediaObject->errorString()));
462 case Phonon::PlayingState:
463 pauseAct->setEnabled(true);
464 pauseAct->setIcon(QtIconLoader::icon("media-pause", QIcon(":/images/pause.png")));
465 pauseAct->setText(tr("&Pause"));
466 pauseAct->setStatusTip(tr("Pause playback"));
467 skipAct->setEnabled(true);
470 case Phonon::StoppedState:
471 pauseAct->setEnabled(false);
472 skipAct->setEnabled(false);
475 case Phonon::PausedState:
476 skipAct->setEnabled(true);
477 pauseAct->setEnabled(true);
478 pauseAct->setIcon(QtIconLoader::icon("media-play", QIcon(":/images/play.png")));
479 pauseAct->setText(tr("&Play"));
480 pauseAct->setStatusTip(tr("Resume playback"));
483 case Phonon::BufferingState:
484 case Phonon::LoadingState:
485 skipAct->setEnabled(true);
486 pauseAct->setEnabled(false);
487 currentTime->clear();
496 void MainWindow::stop() {
501 void MainWindow::fullscreen() {
503 setUpdatesEnabled(false);
506 // use setShortucs instead of setShortcut
507 // the latter seems not to work
508 QList<QKeySequence> shortcuts;
509 shortcuts << QKeySequence(Qt::ALT + Qt::Key_Return);
510 fullscreenAct->setShortcuts(shortcuts);
511 fullscreenAct->setText(tr("&Full Screen"));
512 stopAct->setShortcut(QKeySequence(Qt::Key_Escape));
513 if (m_maximized) showMaximized();
516 stopAct->setShortcut(QString(""));
517 QList<QKeySequence> shortcuts;
518 // for some reason it is important that ESC comes first
519 shortcuts << QKeySequence(Qt::Key_Escape) << QKeySequence(Qt::ALT + Qt::Key_Return);
520 fullscreenAct->setShortcuts(shortcuts);
521 fullscreenAct->setText(tr("Exit &Full Screen"));
522 m_maximized = isMaximized();
524 // save geometry now, if the user quits when in full screen
525 // geometry won't be saved
531 // No compact view action when in full screen
532 compactViewAct->setVisible(m_fullscreen);
533 // Also no Youtube action since it opens a new window
534 webPageAct->setVisible(m_fullscreen);
536 // Hide anything but the video
537 mediaView->setPlaylistVisible(m_fullscreen);
538 mainToolBar->setVisible(m_fullscreen);
539 statusBar()->setVisible(m_fullscreen);
540 menuBar()->setVisible(m_fullscreen);
542 m_fullscreen = !m_fullscreen;
544 setUpdatesEnabled(true);
547 void MainWindow::compactView(bool enable) {
549 setUpdatesEnabled(false);
551 // setUnifiedTitleAndToolBarOnMac(!enable);
552 mediaView->setPlaylistVisible(!enable);
553 mainToolBar->setVisible(!enable);
554 statusBar()->setVisible(!enable);
556 // ensure focus does not end up to the search box
557 // as it would steal the Space shortcut
558 toolbarSearch->setEnabled(!enable);
561 stopAct->setShortcut(QString(""));
562 QList<QKeySequence> shortcuts;
563 // for some reason it is important that ESC comes first
564 shortcuts << QKeySequence(Qt::CTRL + Qt::Key_Return) << QKeySequence(Qt::Key_Escape);
565 compactViewAct->setShortcuts(shortcuts);
567 compactViewAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Return));
568 stopAct->setShortcut(QKeySequence(Qt::Key_Escape));
571 setUpdatesEnabled(true);
574 void MainWindow::searchFocus() {
575 QWidget *view = views->currentWidget();
576 if (view == mediaView) {
577 toolbarSearch->setFocus();
581 void MainWindow::initPhonon() {
582 // Phonon initialization
583 if (mediaObject) delete mediaObject;
584 if (audioOutput) delete audioOutput;
585 mediaObject = new Phonon::MediaObject(this);
586 mediaObject->setTickInterval(100);
587 connect(mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
588 this, SLOT(stateChanged(Phonon::State, Phonon::State)));
589 connect(mediaObject, SIGNAL(tick(qint64)), this, SLOT(tick(qint64)));
590 connect(mediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64)));
591 seekSlider->setMediaObject(mediaObject);
592 audioOutput = new Phonon::AudioOutput(Phonon::VideoCategory, this);
593 connect(audioOutput, SIGNAL(volumeChanged(qreal)), this, SLOT(volumeChanged(qreal)));
594 connect(audioOutput, SIGNAL(mutedChanged(bool)), this, SLOT(volumeMutedChanged(bool)));
595 volumeSlider->setAudioOutput(audioOutput);
596 Phonon::createPath(mediaObject, audioOutput);
599 void MainWindow::tick(qint64 time) {
601 currentTime->clear();
604 QTime displayTime(0, (time / 60000) % 60, (time / 1000) % 60);
605 currentTime->setText(displayTime.toString("mm:ss"));
606 // qDebug() << "currentTime" << time << displayTime.toString("mm:ss");
609 void MainWindow::totalTimeChanged(qint64 time) {
614 QTime displayTime(0, (time / 60000) % 60, (time / 1000) % 60);
615 totalTime->setText(displayTime.toString("/ mm:ss"));
616 // qDebug() << "totalTime" << time << displayTime.toString("mm:ss");
619 void MainWindow::volumeUp() {
620 qreal newVolume = volumeSlider->audioOutput()->volume() + .1;
621 if (newVolume > volumeSlider->maximumVolume())
622 newVolume = volumeSlider->maximumVolume();
623 volumeSlider->audioOutput()->setVolume(newVolume);
626 void MainWindow::volumeDown() {
627 qreal newVolume = volumeSlider->audioOutput()->volume() - .1;
630 volumeSlider->audioOutput()->setVolume(newVolume);
633 void MainWindow::volumeMute() {
634 volumeSlider->audioOutput()->setMuted(!volumeSlider->audioOutput()->isMuted());
637 void MainWindow::volumeChanged(qreal newVolume) {
638 // automatically unmute when volume changes
639 if (volumeSlider->audioOutput()->isMuted())
640 volumeSlider->audioOutput()->setMuted(false);
641 statusBar()->showMessage(tr("Volume at %1%").arg(newVolume*100));
644 void MainWindow::volumeMutedChanged(bool muted) {
646 statusBar()->showMessage(tr("Volume is muted"));
648 statusBar()->showMessage(tr("Volume is unmuted"));
652 void MainWindow::abortDownload() {
653 QProgressDialog* dlg = dynamic_cast<QProgressDialog*>(this->sender());
654 QMap<QNetworkReply*, DownloadResource>::iterator cur;
655 QMap<QNetworkReply*, DownloadResource>::iterator end;
656 // locate the DownloadResource by its dialog address and trigger abortion
657 for(cur=m_downloads.begin(), end=m_downloads.end(); cur!=end; cur++){
658 if(cur.value().dialog == dlg) cur.key()->abort();
662 void MainWindow::download() {
663 if(mediaObject == NULL || mediaObject->currentSource().url().isEmpty()){
664 // complain unless video source apperas to be valid
665 QMessageBox::critical(this, tr("No Video playing"), tr("You must first play the video you intent to download !"));
668 QString filename = QFileDialog::getSaveFileName(this,
669 tr("Save video as..."),
670 tr("minitube video.mp4"),
671 "Video File(*.avi *.mp4)"
673 if(!filename.isNull()) {
674 // open destination file and initialize download
675 DownloadResource res;
676 res.file = new QFile(filename);
677 if(res.file->open(QFile::WriteOnly) == true) {
678 res.dialog = new QProgressDialog(tr("Downloading: ") + res.file->fileName(),
679 tr("Abort Download"), 0, 100, this);
680 connect(res.dialog, SIGNAL(canceled()), this, SLOT(abortDownload()));
681 download(mediaObject->currentSource().url(), res);
683 QMessageBox::critical(this, tr("File creation failed"), res.file->errorString());
689 void MainWindow::download(const QUrl& url, const DownloadResource& res) {
690 // create and store request and connect the reply signals
691 QNetworkReply *r = The::networkAccessManager()->get(QNetworkRequest(url));
692 m_downloads.insert(r, res);
693 connect(r, SIGNAL(finished()), this, SLOT(replyFinished()));
694 connect(r, SIGNAL(readyRead()), this, SLOT(replyReadyRead()));
695 connect(r, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(replyError(QNetworkReply::NetworkError)));
696 connect(r, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(replyDownloadProgress(qint64,qint64)));
697 connect(r, SIGNAL(metaDataChanged()), this, SLOT(replyMetaDataChanged()));
700 void MainWindow::replyReadyRead() {
701 QNetworkReply* r = dynamic_cast<QNetworkReply*>(this->sender());
702 m_downloads[r].file->write(r->readAll());
705 void MainWindow::replyDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) {
706 QNetworkReply* r = dynamic_cast<QNetworkReply*>(this->sender());
707 if (bytesTotal > 0 && bytesReceived >0)
708 m_downloads[r].dialog->setValue( double(100.0/bytesTotal)*bytesReceived ); // pssst :-X
711 void MainWindow::replyError(QNetworkReply::NetworkError code) {
712 QNetworkReply* r = dynamic_cast<QNetworkReply*>(this->sender());
713 QMessageBox::critical(this, tr("Download failed"), r->errorString());
716 void MainWindow::replyFinished() {
717 QNetworkReply* r = dynamic_cast<QNetworkReply*>(this->sender());
718 m_downloads[r].dialog->close();
719 m_downloads[r].file->close();
720 delete m_downloads[r].file;
721 m_downloads.remove(r);
724 void MainWindow::replyMetaDataChanged() {
725 QNetworkReply* r = dynamic_cast<QNetworkReply*>(this->sender());
726 QUrl url = r->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
728 // redirect - request new url, but keep the resources
729 qDebug() << "redirecting to: " << url.toString();
730 download(url, m_downloads[r]);
731 m_downloads.remove(r);