/*************************************************************************** * Copyright (c) 2013 Werner Mayer * * * * This file is part of the FreeCAD CAx development system. * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Library General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Library General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this library; see the file COPYING.LIB. If not, * * write to the Free Software Foundation, Inc., 59 Temple Place, * * Suite 330, Boston, MA 02111-1307, USA * * * ***************************************************************************/ #include "PreCompiled.h" #include #include #include #include #include #include #include #include #include #include #include #include "DownloadItem.h" #include "DownloadManager.h" #include "ui_DownloadManager.h" #include "DockWindowManager.h" #include "MainWindow.h" using namespace Gui::Dialog; /* TRANSLATOR Gui::Dialog::DownloadManager */ DownloadManager* DownloadManager::self = 0; DownloadManager* DownloadManager::getInstance() { if (!self) self = new DownloadManager(Gui::getMainWindow()); return self; } DownloadManager::DownloadManager(QWidget *parent) : QDialog(parent) , m_autoSaver(new AutoSaver(this)) , m_manager(new NetworkAccessManager(this)) , m_iconProvider(0) , m_removePolicy(Never) , ui(new Ui_DownloadManager()) { ui->setupUi(this); ui->downloadsView->setShowGrid(false); ui->downloadsView->verticalHeader()->hide(); ui->downloadsView->horizontalHeader()->hide(); ui->downloadsView->setAlternatingRowColors(true); ui->downloadsView->horizontalHeader()->setStretchLastSection(true); m_model = new DownloadModel(this); ui->downloadsView->setModel(m_model); connect(ui->cleanupButton, SIGNAL(clicked()), this, SLOT(cleanup())); connect(m_manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*))); load(); Gui::DockWindowManager* pDockMgr = Gui::DockWindowManager::instance(); QDockWidget* dw = pDockMgr->addDockWindow(QT_TR_NOOP("Download Manager"), this, Qt::BottomDockWidgetArea); dw->setFeatures(QDockWidget::DockWidgetMovable| QDockWidget::DockWidgetFloatable| QDockWidget::DockWidgetClosable); dw->setAttribute(Qt::WA_DeleteOnClose); dw->show(); } DownloadManager::~DownloadManager() { m_autoSaver->changeOccurred(); m_autoSaver->saveIfNeccessary(); if (m_iconProvider) delete m_iconProvider; delete ui; self = 0; } void DownloadManager::closeEvent(QCloseEvent* e) { QDialog::closeEvent(e); } int DownloadManager::activeDownloads() const { int count = 0; for (int i = 0; i < m_downloads.count(); ++i) { if (m_downloads.at(i)->stopButton->isEnabled()) ++count; } return count; } QUrl DownloadManager::redirectUrl(const QUrl& url) const { QUrl redirectUrl = url; if (url.host() == QLatin1String("www.dropbox.com")) { QList< QPair > query = url.queryItems(); for (QList< QPair >::iterator it = query.begin(); it != query.end(); ++it) { if (it->first == QLatin1String("dl") && it->second == QLatin1String("0\r\n")) { redirectUrl.removeQueryItem(QLatin1String("dl")); redirectUrl.addQueryItem(QLatin1String("dl"), QLatin1String("1\r\n")); break; } } } else { // When the url comes from drag and drop it may end with CR+LF. This may cause problems // and thus should be removed. QString str = redirectUrl.toString(); if (str.endsWith(QLatin1String("\r\n"))) { str.chop(2); redirectUrl.setUrl(str); } } return redirectUrl; } void DownloadManager::replyFinished(QNetworkReply* reply) { // The 'requestFileName' is used to store the argument passed by 'download()' // and to also distinguish between replies created by 'download()' and // this method. // Replies from this method shouldn't be further examined because it's not // assumed to get re-directed urls over several steps. QVariant var = reply->property("requestFileName"); if (var.isValid()) { bool requestFileName = reply->property("requestFileName").toBool(); QUrl url = reply->url(); // If this is a redirected url use this instead QUrl redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); if (!redirectUrl.isEmpty()) { url = redirectUrl; } // start the actual download now handleUnsupportedContent(m_manager->get(QNetworkRequest(url)), requestFileName); } reply->deleteLater(); } void DownloadManager::download(const QNetworkRequest &request, bool requestFileName) { if (request.url().isEmpty()) return; std::cout << request.url().toString().toStdString() << std::endl; // postpone this reply until we can examine it in replyFinished QNetworkReply* reply = m_manager->get(request); reply->setProperty("requestFileName", QVariant(requestFileName)); } void DownloadManager::handleUnsupportedContent(QNetworkReply *reply, bool requestFileName) { if (!reply || reply->url().isEmpty()) return; QVariant header = reply->header(QNetworkRequest::ContentLengthHeader); bool ok; int size = header.toInt(&ok); if (ok && size == 0) return; DownloadItem *item = new DownloadItem(reply, requestFileName, this); addItem(item); } void DownloadManager::addItem(DownloadItem *item) { connect(item, SIGNAL(statusChanged()), this, SLOT(updateRow())); int row = m_downloads.count(); m_model->beginInsertRows(QModelIndex(), row, row); m_downloads.append(item); m_model->endInsertRows(); updateItemCount(); show(); ui->downloadsView->setIndexWidget(m_model->index(row, 0), item); QIcon icon = style()->standardIcon(QStyle::SP_FileIcon); item->fileIcon->setPixmap(icon.pixmap(48, 48)); ui->downloadsView->setRowHeight(row, item->sizeHint().height()); } void DownloadManager::updateRow() { DownloadItem *item = qobject_cast(sender()); int row = m_downloads.indexOf(item); if (-1 == row) return; if (!m_iconProvider) m_iconProvider = new QFileIconProvider(); QIcon icon = m_iconProvider->icon(item->m_output.fileName()); if (icon.isNull()) icon = style()->standardIcon(QStyle::SP_FileIcon); item->fileIcon->setPixmap(icon.pixmap(48, 48)); ui->downloadsView->setRowHeight(row, item->minimumSizeHint().height()); bool remove = false; QWebSettings *globalSettings = QWebSettings::globalSettings(); if (!item->downloading() && globalSettings->testAttribute(QWebSettings::PrivateBrowsingEnabled)) remove = true; if (item->downloadedSuccessfully() && removePolicy() == DownloadManager::SuccessFullDownload) { remove = true; } if (remove) m_model->removeRow(row); ui->cleanupButton->setEnabled(m_downloads.count() - activeDownloads() > 0); } DownloadManager::RemovePolicy DownloadManager::removePolicy() const { return m_removePolicy; } void DownloadManager::setRemovePolicy(RemovePolicy policy) { if (policy == m_removePolicy) return; m_removePolicy = policy; m_autoSaver->changeOccurred(); } void DownloadManager::save() const { QSettings settings; settings.beginGroup(QLatin1String("downloadmanager")); QMetaEnum removePolicyEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("RemovePolicy")); settings.setValue(QLatin1String("removeDownloadsPolicy"), QLatin1String(removePolicyEnum.valueToKey(m_removePolicy))); settings.setValue(QLatin1String("size"), size()); if (m_removePolicy == Exit) return; for (int i = 0; i < m_downloads.count(); ++i) { QString key = QString(QLatin1String("download_%1_")).arg(i); settings.setValue(key + QLatin1String("url"), m_downloads[i]->m_url); settings.setValue(key + QLatin1String("location"), QFileInfo(m_downloads[i]->m_output).filePath()); settings.setValue(key + QLatin1String("done"), m_downloads[i]->downloadedSuccessfully()); } int i = m_downloads.count(); QString key = QString(QLatin1String("download_%1_")).arg(i); while (settings.contains(key + QLatin1String("url"))) { settings.remove(key + QLatin1String("url")); settings.remove(key + QLatin1String("location")); settings.remove(key + QLatin1String("done")); key = QString(QLatin1String("download_%1_")).arg(++i); } } void DownloadManager::load() { QSettings settings; settings.beginGroup(QLatin1String("downloadmanager")); QSize size = settings.value(QLatin1String("size")).toSize(); if (size.isValid()) resize(size); QByteArray value = settings.value(QLatin1String("removeDownloadsPolicy"), QLatin1String("Never")).toByteArray(); QMetaEnum removePolicyEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("RemovePolicy")); m_removePolicy = removePolicyEnum.keyToValue(value) == -1 ? Never : static_cast(removePolicyEnum.keyToValue(value)); int i = 0; QString key = QString(QLatin1String("download_%1_")).arg(i); while (settings.contains(key + QLatin1String("url"))) { QUrl url = settings.value(key + QLatin1String("url")).toUrl(); QString fileName = settings.value(key + QLatin1String("location")).toString(); bool done = settings.value(key + QLatin1String("done"), true).toBool(); if (!url.isEmpty() && !fileName.isEmpty()) { DownloadItem *item = new DownloadItem(0, this); item->m_output.setFileName(fileName); item->fileNameLabel->setText(QFileInfo(item->m_output.fileName()).fileName()); item->m_url = url; item->stopButton->setVisible(false); item->stopButton->setEnabled(false); item->tryAgainButton->setVisible(!done); item->tryAgainButton->setEnabled(!done); item->progressBar->setVisible(!done); addItem(item); } key = QString(QLatin1String("download_%1_")).arg(++i); } ui->cleanupButton->setEnabled(m_downloads.count() - activeDownloads() > 0); } void DownloadManager::cleanup() { if (m_downloads.isEmpty()) return; m_model->removeRows(0, m_downloads.count()); updateItemCount(); if (m_downloads.isEmpty() && m_iconProvider) { delete m_iconProvider; m_iconProvider = 0; } m_autoSaver->changeOccurred(); } void DownloadManager::updateItemCount() { int count = m_downloads.count(); ui->itemCount->setText(count == 1 ? tr("1 Download") : tr("%1 Downloads").arg(count)); } // ---------------------------------------------------------------------------- DownloadModel::DownloadModel(DownloadManager *downloadManager, QObject *parent) : QAbstractListModel(parent) , m_downloadManager(downloadManager) { } QVariant DownloadModel::data(const QModelIndex &index, int role) const { if (index.row() < 0 || index.row() >= rowCount(index.parent())) return QVariant(); if (role == Qt::ToolTipRole) if (!m_downloadManager->m_downloads.at(index.row())->downloadedSuccessfully()) return m_downloadManager->m_downloads.at(index.row())->downloadInfoLabel->text(); return QVariant(); } int DownloadModel::rowCount(const QModelIndex &parent) const { return (parent.isValid()) ? 0 : m_downloadManager->m_downloads.count(); } bool DownloadModel::removeRows(int row, int count, const QModelIndex &parent) { if (parent.isValid()) return false; int lastRow = row + count - 1; for (int i = lastRow; i >= row; --i) { if (m_downloadManager->m_downloads.at(i)->downloadedSuccessfully() || m_downloadManager->m_downloads.at(i)->tryAgainButton->isEnabled()) { beginRemoveRows(parent, i, i); m_downloadManager->m_downloads.takeAt(i)->deleteLater(); endRemoveRows(); } } m_downloadManager->m_autoSaver->changeOccurred(); return true; } #include "moc_DownloadManager.cpp"