0000952: Download manager

This commit is contained in:
wmayer 2013-05-28 18:14:58 +02:00
parent 2e31e177a8
commit 3db10284b1
13 changed files with 1699 additions and 4 deletions

View File

@ -99,6 +99,8 @@ set(Gui_MOC_HDRS
Control.h
DemoMode.h
DownloadDialog.h
DownloadItem.h
DownloadManager.h
DlgActionsImp.h
DlgActivateWindowImp.h
DlgCommandsImp.h
@ -220,6 +222,8 @@ SET(Gui_UIC_SRCS
DlgTreeWidget.ui
DlgLocationAngle.ui
DlgLocationPos.ui
DownloadManager.ui
DownloadItem.ui
MouseButtons.ui
SceneInspector.ui
InputVector.ui
@ -282,6 +286,8 @@ SET(Dialog_CPP_SRCS
TextureMapping.cpp
Transform.cpp
DownloadDialog.cpp
DownloadItem.cpp
DownloadManager.cpp
)
SET(Dialog_HPP_SRCS
@ -307,6 +313,8 @@ SET(Dialog_HPP_SRCS
TextureMapping.h
Transform.h
DownloadDialog.h
DownloadItem.h
DownloadManager.h
)
SET(Dialog_SRCS
@ -327,6 +335,8 @@ SET(Dialog_SRCS
DlgProjectUtility.ui
DlgTipOfTheDay.ui
DlgTreeWidget.ui
DownloadManager.ui
DownloadItem.ui
MouseButtons.ui
InputVector.ui
Placement.ui

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>304</width>
<height>189</height>
<width>284</width>
<height>128</height>
</rect>
</property>
<property name="windowTitle">

536
src/Gui/DownloadItem.cpp Normal file
View File

@ -0,0 +1,536 @@
/***************************************************************************
* Copyright (c) 2013 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* 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 <stdio.h>
#include <math.h>
#include <QAuthenticator>
#include <QFileInfo>
#include <QNetworkDiskCache>
#include <QNetworkRequest>
#include <QNetworkProxy>
#include <QSettings>
#include <QMetaObject>
#include <QDesktopServices>
#include <QFileDialog>
#include <QHeaderView>
#include <QDebug>
#include <QKeyEvent>
#include <QTextDocument>
#include <App/Document.h>
#include "DownloadItem.h"
#include "DownloadManager.h"
#include "Application.h"
#include "Document.h"
#include "MainWindow.h"
#include "FileDialog.h"
#include "ui_DlgAuthorization.h"
using namespace Gui::Dialog;
EditTableView::EditTableView(QWidget *parent)
: QTableView(parent)
{
}
void EditTableView::keyPressEvent(QKeyEvent *event)
{
if ((event->key() == Qt::Key_Delete
|| event->key() == Qt::Key_Backspace)
&& model()) {
removeOne();
} else {
QAbstractItemView::keyPressEvent(event);
}
}
void EditTableView::removeOne()
{
if (!model() || !selectionModel())
return;
int row = currentIndex().row();
model()->removeRow(row, rootIndex());
QModelIndex idx = model()->index(row, 0, rootIndex());
if (!idx.isValid())
idx = model()->index(row - 1, 0, rootIndex());
selectionModel()->select(idx, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
}
void EditTableView::removeAll()
{
if (model())
model()->removeRows(0, model()->rowCount(rootIndex()), rootIndex());
}
// ----------------------------------------------------------------------------
SqueezeLabel::SqueezeLabel(QWidget *parent) : QLabel(parent)
{
}
void SqueezeLabel::paintEvent(QPaintEvent *event)
{
QFontMetrics fm = fontMetrics();
if (fm.width(text()) > contentsRect().width()) {
QString elided = fm.elidedText(text(), Qt::ElideMiddle, width());
QString oldText = text();
setText(elided);
QLabel::paintEvent(event);
setText(oldText);
} else {
QLabel::paintEvent(event);
}
}
// ----------------------------------------------------------------------------
#define AUTOSAVE_IN 1000 * 3 // seconds
#define MAXWAIT 1000 * 15 // seconds
AutoSaver::AutoSaver(QObject *parent) : QObject(parent)
{
Q_ASSERT(parent);
}
AutoSaver::~AutoSaver()
{
if (m_timer.isActive())
qWarning() << "AutoSaver: still active when destroyed, changes not saved.";
}
void AutoSaver::changeOccurred()
{
if (m_firstChange.isNull())
m_firstChange.start();
if (m_firstChange.elapsed() > MAXWAIT) {
saveIfNeccessary();
} else {
m_timer.start(AUTOSAVE_IN, this);
}
}
void AutoSaver::timerEvent(QTimerEvent *event)
{
if (event->timerId() == m_timer.timerId()) {
saveIfNeccessary();
} else {
QObject::timerEvent(event);
}
}
void AutoSaver::saveIfNeccessary()
{
if (!m_timer.isActive())
return;
m_timer.stop();
m_firstChange = QTime();
if (!QMetaObject::invokeMethod(parent(), "save", Qt::DirectConnection)) {
qWarning() << "AutoSaver: error invoking slot save() on parent";
}
}
// ----------------------------------------------------------------------------
NetworkAccessManager::NetworkAccessManager(QObject *parent)
: QNetworkAccessManager(parent)
{
connect(this, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)),
SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
connect(this, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*)),
SLOT(proxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*)));
QNetworkDiskCache *diskCache = new QNetworkDiskCache(this);
QString location = QDesktopServices::storageLocation(QDesktopServices::CacheLocation);
diskCache->setCacheDirectory(location);
setCache(diskCache);
}
void NetworkAccessManager::authenticationRequired(QNetworkReply *reply, QAuthenticator *auth)
{
QWidget *mainWindow = Gui::getMainWindow();
QDialog dialog(mainWindow);
dialog.setWindowFlags(Qt::Sheet);
Ui_DlgAuthorization passwordDialog;
passwordDialog.setupUi(&dialog);
dialog.adjustSize();
QString introMessage = tr("<qt>Enter username and password for \"%1\" at %2</qt>");
introMessage = introMessage.arg(Qt::escape(reply->url().toString())).arg(Qt::escape(reply->url().toString()));
passwordDialog.siteDescription->setText(introMessage);
passwordDialog.siteDescription->setWordWrap(true);
if (dialog.exec() == QDialog::Accepted) {
auth->setUser(passwordDialog.username->text());
auth->setPassword(passwordDialog.password->text());
}
}
void NetworkAccessManager::proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *auth)
{
QWidget *mainWindow = Gui::getMainWindow();
QDialog dialog(mainWindow);
dialog.setWindowFlags(Qt::Sheet);
Ui_DlgAuthorization proxyDialog;
proxyDialog.setupUi(&dialog);
dialog.adjustSize();
QString introMessage = tr("<qt>Connect to proxy \"%1\" using:</qt>");
introMessage = introMessage.arg(Qt::escape(proxy.hostName()));
proxyDialog.siteDescription->setText(introMessage);
proxyDialog.siteDescription->setWordWrap(true);
if (dialog.exec() == QDialog::Accepted) {
auth->setUser(proxyDialog.username->text());
auth->setPassword(proxyDialog.password->text());
}
}
// ----------------------------------------------------------------------------
DownloadItem::DownloadItem(QNetworkReply *reply, bool requestFileName, QWidget *parent)
: QWidget(parent)
, m_reply(reply)
, m_requestFileName(requestFileName)
, m_bytesReceived(0)
{
setupUi(this);
QPalette p = downloadInfoLabel->palette();
p.setColor(QPalette::Text, Qt::darkGray);
downloadInfoLabel->setPalette(p);
progressBar->setMaximum(0);
tryAgainButton->hide();
connect(stopButton, SIGNAL(clicked()), this, SLOT(stop()));
connect(openButton, SIGNAL(clicked()), this, SLOT(open()));
connect(tryAgainButton, SIGNAL(clicked()), this, SLOT(tryAgain()));
init();
}
void DownloadItem::init()
{
if (!m_reply)
return;
// attach to the m_reply
m_url = m_reply->url();
m_reply->setParent(this);
connect(m_reply, SIGNAL(readyRead()), this, SLOT(downloadReadyRead()));
connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(error(QNetworkReply::NetworkError)));
connect(m_reply, SIGNAL(downloadProgress(qint64, qint64)),
this, SLOT(downloadProgress(qint64, qint64)));
connect(m_reply, SIGNAL(metaDataChanged()),
this, SLOT(metaDataChanged()));
connect(m_reply, SIGNAL(finished()),
this, SLOT(finished()));
// reset info
downloadInfoLabel->clear();
progressBar->setValue(0);
getFileName();
// start timer for the download estimation
m_downloadTime.start();
if (m_reply->error() != QNetworkReply::NoError) {
error(m_reply->error());
finished();
}
}
void DownloadItem::getFileName()
{
QSettings settings;
settings.beginGroup(QLatin1String("downloadmanager"));
//QString defaultLocation = QDesktopServices::storageLocation(QDesktopServices::DesktopLocation);
QString defaultLocation = Gui::FileDialog::getWorkingDirectory();
QString downloadDirectory = settings.value(QLatin1String("downloadDirectory"), defaultLocation).toString();
if (!downloadDirectory.isEmpty())
downloadDirectory += QLatin1Char('/');
QString defaultFileName = saveFileName(downloadDirectory);
QString fileName = defaultFileName;
if (m_requestFileName) {
fileName = QFileDialog::getSaveFileName(this, tr("Save File"), defaultFileName);
if (fileName.isEmpty()) {
m_reply->close();
fileNameLabel->setText(tr("Download canceled: %1").arg(QFileInfo(defaultFileName).fileName()));
return;
}
}
m_output.setFileName(fileName);
fileNameLabel->setText(QFileInfo(m_output.fileName()).fileName());
if (m_requestFileName)
downloadReadyRead();
}
QString DownloadItem::saveFileName(const QString &directory) const
{
// Move this function into QNetworkReply to also get file name sent from the server
QString path = m_url.path();
if (!m_fileName.isEmpty())
path = m_fileName;
QFileInfo info(path);
QString baseName = info.completeBaseName();
QString endName = info.suffix();
if (baseName.isEmpty()) {
baseName = QLatin1String("unnamed_download");
qDebug() << "DownloadManager:: downloading unknown file:" << m_url;
}
QString name = directory + baseName + QLatin1Char('.') + endName;
if (QFile::exists(name)) {
// already exists, don't overwrite
int i = 1;
do {
name = directory + baseName + QLatin1Char('-') + QString::number(i++) + QLatin1Char('.') + endName;
} while (QFile::exists(name));
}
return name;
}
void DownloadItem::stop()
{
setUpdatesEnabled(false);
stopButton->setEnabled(false);
stopButton->hide();
tryAgainButton->setEnabled(true);
tryAgainButton->show();
setUpdatesEnabled(true);
m_reply->abort();
}
void DownloadItem::open()
{
QFileInfo info(m_output);
QString selectedFilter;
QStringList fileList;
fileList << info.absoluteFilePath();
SelectModule::Dict dict = SelectModule::importHandler(fileList, selectedFilter);
// load the files with the associated modules
if (!dict.isEmpty()) {
Gui::Document* doc = Gui::Application::Instance->activeDocument();
if (doc) {
for (SelectModule::Dict::iterator it = dict.begin(); it != dict.end(); ++it) {
Gui::Application::Instance->importFrom(it.key().toUtf8(),
doc->getDocument()->getName(), it.value().toAscii());
}
}
else {
for (SelectModule::Dict::iterator it = dict.begin(); it != dict.end(); ++it) {
Gui::Application::Instance->open(it.key().toUtf8(), it.value().toAscii());
}
}
}
else {
QUrl url = QUrl::fromLocalFile(info.absolutePath());
QDesktopServices::openUrl(url);
}
}
void DownloadItem::tryAgain()
{
if (!tryAgainButton->isEnabled())
return;
tryAgainButton->setEnabled(false);
tryAgainButton->setVisible(false);
stopButton->setEnabled(true);
stopButton->setVisible(true);
progressBar->setVisible(true);
QNetworkReply *r = DownloadManager::getInstance()->networkAccessManager()->get(QNetworkRequest(m_url));
if (m_reply)
m_reply->deleteLater();
if (m_output.exists())
m_output.remove();
m_reply = r;
init();
/*emit*/ statusChanged();
}
void DownloadItem::downloadReadyRead()
{
if (m_requestFileName && m_output.fileName().isEmpty())
return;
if (!m_output.isOpen()) {
// in case someone else has already put a file there
if (!m_requestFileName)
getFileName();
if (!m_output.open(QIODevice::WriteOnly)) {
downloadInfoLabel->setText(tr("Error opening save file: %1")
.arg(m_output.errorString()));
stopButton->click();
/*emit*/ statusChanged();
return;
}
/*emit*/ statusChanged();
}
if (-1 == m_output.write(m_reply->readAll())) {
downloadInfoLabel->setText(tr("Error saving: %1")
.arg(m_output.errorString()));
stopButton->click();
}
}
void DownloadItem::error(QNetworkReply::NetworkError)
{
qDebug() << "DownloadItem::error" << m_reply->errorString() << m_url;
downloadInfoLabel->setText(tr("Network Error: %1").arg(m_reply->errorString()));
tryAgainButton->setEnabled(true);
tryAgainButton->setVisible(true);
}
void DownloadItem::metaDataChanged()
{
if (m_reply->hasRawHeader(QByteArray("Content-Disposition"))) {
QByteArray header = m_reply->rawHeader(QByteArray("Content-Disposition"));
int index = header.indexOf("filename=");
if (index > 0) {
header = header.mid(index+9);
m_fileName = QUrl::fromPercentEncoding(header);
}
else {
index = header.indexOf("filename*=UTF-8''");
if (index > 0) {
header = header.mid(index+17);
m_fileName = QUrl::fromPercentEncoding(header);
}
}
}
QVariant statusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
if (!statusCode.isValid())
return;
int status = statusCode.toInt();
if (status != 200) {
QString reason = m_reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
qDebug() << reason;
}
}
void DownloadItem::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
{
m_bytesReceived = bytesReceived;
if (bytesTotal == -1) {
progressBar->setValue(0);
progressBar->setMaximum(0);
} else {
progressBar->setValue(bytesReceived);
progressBar->setMaximum(bytesTotal);
}
updateInfoLabel();
}
void DownloadItem::updateInfoLabel()
{
if (m_reply->error() == QNetworkReply::NoError)
return;
qint64 bytesTotal = progressBar->maximum();
bool running = !downloadedSuccessfully();
// update info label
double speed = m_bytesReceived * 1000.0 / m_downloadTime.elapsed();
double timeRemaining = ((double)(bytesTotal - m_bytesReceived)) / speed;
QString timeRemainingString = tr("seconds");
if (timeRemaining > 60) {
timeRemaining = timeRemaining / 60;
timeRemainingString = tr("minutes");
}
timeRemaining = floor(timeRemaining);
// When downloading the eta should never be 0
if (timeRemaining == 0)
timeRemaining = 1;
QString info;
if (running) {
QString remaining;
if (bytesTotal != 0)
remaining = tr("- %4 %5 remaining")
.arg(timeRemaining)
.arg(timeRemainingString);
info = QString(tr("%1 of %2 (%3/sec) %4"))
.arg(dataString(m_bytesReceived))
.arg(bytesTotal == 0 ? tr("?") : dataString(bytesTotal))
.arg(dataString((int)speed))
.arg(remaining);
} else {
if (m_bytesReceived == bytesTotal)
info = dataString(m_output.size());
else
info = tr("%1 of %2 - Stopped")
.arg(dataString(m_bytesReceived))
.arg(dataString(bytesTotal));
}
downloadInfoLabel->setText(info);
}
QString DownloadItem::dataString(int size) const
{
QString unit;
if (size < 1024) {
unit = tr("bytes");
} else if (size < 1024*1024) {
size /= 1024;
unit = tr("kB");
} else {
size /= 1024*1024;
unit = tr("MB");
}
return QString(QLatin1String("%1 %2")).arg(size).arg(unit);
}
bool DownloadItem::downloading() const
{
return (progressBar->isVisible());
}
bool DownloadItem::downloadedSuccessfully() const
{
return (stopButton->isHidden() && tryAgainButton->isHidden());
}
void DownloadItem::finished()
{
progressBar->hide();
stopButton->setEnabled(false);
stopButton->hide();
m_output.close();
updateInfoLabel();
/*emit*/ statusChanged();
}
#include "moc_DownloadItem.cpp"

153
src/Gui/DownloadItem.h Normal file
View File

@ -0,0 +1,153 @@
/***************************************************************************
* Copyright (c) 2013 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* 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 *
* *
***************************************************************************/
#ifndef GUI_DIALOG_DOWNLOADITEM_H
#define GUI_DIALOG_DOWNLOADITEM_H
#include <QBasicTimer>
#include <QFile>
#include <QTime>
#include <QUrl>
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QLabel>
#include <QTableView>
class AutoSaver;
class QFileIconProvider;
class EditTableView : public QTableView
{
Q_OBJECT
public:
EditTableView(QWidget *parent = 0);
void keyPressEvent(QKeyEvent *event);
public Q_SLOTS:
void removeOne();
void removeAll();
};
class SqueezeLabel : public QLabel
{
Q_OBJECT
public:
SqueezeLabel(QWidget *parent = 0);
protected:
void paintEvent(QPaintEvent *event);
};
/*
This class will call the save() slot on the parent object when the parent changes.
It will wait several seconds after changed() to combining multiple changes and
prevent continuous writing to disk.
*/
class AutoSaver : public QObject {
Q_OBJECT
public:
AutoSaver(QObject *parent);
~AutoSaver();
void saveIfNeccessary();
public Q_SLOTS:
void changeOccurred();
protected:
void timerEvent(QTimerEvent *event);
private:
QBasicTimer m_timer;
QTime m_firstChange;
};
class NetworkAccessManager : public QNetworkAccessManager
{
Q_OBJECT
public:
NetworkAccessManager(QObject *parent = 0);
private Q_SLOTS:
void authenticationRequired(QNetworkReply *reply, QAuthenticator *auth);
void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *auth);
};
#include "ui_DownloadItem.h"
namespace Gui {
namespace Dialog {
class DownloadModel;
class DownloadItem : public QWidget, public Ui_DownloadItem
{
Q_OBJECT
Q_SIGNALS:
void statusChanged();
public:
DownloadItem(QNetworkReply *reply = 0, bool requestFileName = false, QWidget *parent = 0);
bool downloading() const;
bool downloadedSuccessfully() const;
QUrl m_url;
QString m_fileName;
QFile m_output;
QNetworkReply *m_reply;
private Q_SLOTS:
void stop();
void tryAgain();
void open();
void downloadReadyRead();
void error(QNetworkReply::NetworkError code);
void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
void metaDataChanged();
void finished();
private:
void getFileName();
void init();
void updateInfoLabel();
QString dataString(int size) const;
QString saveFileName(const QString &directory) const;
bool m_requestFileName;
qint64 m_bytesReceived;
QTime m_downloadTime;
};
} // namespace Dialog
} // namespace Gui
#endif // GUI_DIALOG_DOWNLOADITEM_H

141
src/Gui/DownloadItem.ui Normal file
View File

@ -0,0 +1,141 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DownloadItem</class>
<widget class="QWidget" name="DownloadItem">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>423</width>
<height>98</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="fileIcon">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Ico</string>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="SqueezeLabel" name="fileNameLabel" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text" stdset="0">
<string>Filename</string>
</property>
</widget>
</item>
<item>
<widget class="QProgressBar" name="progressBar">
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item>
<widget class="SqueezeLabel" name="downloadInfoLabel" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text" stdset="0">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>17</width>
<height>1</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="tryAgainButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="icon">
<iconset resource="Icons/resource.qrc">
<normaloff>:/icons/view-refresh.svg</normaloff>:/icons/view-refresh.svg</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="stopButton">
<property name="icon">
<iconset resource="Icons/resource.qrc">
<normaloff>:/icons/process-stop.svg</normaloff>:/icons/process-stop.svg</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="openButton">
<property name="icon">
<iconset resource="Icons/resource.qrc">
<normaloff>:/icons/document-open.svg</normaloff>:/icons/document-open.svg</iconset>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>17</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>SqueezeLabel</class>
<extends>QWidget</extends>
<header>DownloadItem.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="Icons/resource.qrc"/>
<include location="../../../Imetric/FreeCAD/src/Mod/IScan3D/Gui/IScan3D.qrc"/>
</resources>
<connections/>
</ui>

303
src/Gui/DownloadManager.cpp Normal file
View File

@ -0,0 +1,303 @@
/***************************************************************************
* Copyright (c) 2013 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* 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 <stdio.h>
#include <math.h>
#include <QByteArray>
#include <QDockWidget>
#include <QFileInfo>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QMetaEnum>
#include <QSettings>
#include <QFileIconProvider>
#include <QWebSettings>
#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()));
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);
dw->show();
}
DownloadManager::~DownloadManager()
{
m_autoSaver->changeOccurred();
m_autoSaver->saveIfNeccessary();
if (m_iconProvider)
delete m_iconProvider;
delete ui;
}
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;
}
void DownloadManager::download(const QNetworkRequest &request, bool requestFileName)
{
if (request.url().isEmpty())
return;
handleUnsupportedContent(m_manager->get(request), 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<DownloadItem*>(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<RemovePolicy>(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"

116
src/Gui/DownloadManager.h Normal file
View File

@ -0,0 +1,116 @@
/***************************************************************************
* Copyright (c) 2013 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* 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 *
* *
***************************************************************************/
#ifndef GUI_DIALOG_DOWNLOADMANAGER_H
#define GUI_DIALOG_DOWNLOADMANAGER_H
#include <QDialog>
#include <QUrl>
#include <QNetworkAccessManager>
#include <QNetworkReply>
class AutoSaver;
class QFileIconProvider;
namespace Gui {
namespace Dialog {
class DownloadItem;
class DownloadModel;
class Ui_DownloadManager;
class GuiExport DownloadManager : public QDialog
{
Q_OBJECT
Q_PROPERTY(RemovePolicy removePolicy READ removePolicy WRITE setRemovePolicy)
Q_ENUMS(RemovePolicy)
public:
enum RemovePolicy {
Never,
Exit,
SuccessFullDownload
};
static DownloadManager* getInstance();
private:
DownloadManager(QWidget *parent = 0);
~DownloadManager();
public:
int activeDownloads() const;
QNetworkAccessManager * networkAccessManager()
{ return m_manager; }
RemovePolicy removePolicy() const;
void setRemovePolicy(RemovePolicy policy);
public Q_SLOTS:
void download(const QNetworkRequest &request, bool requestFileName = false);
inline void download(const QUrl &url, bool requestFileName = false)
{ download(QNetworkRequest(url), requestFileName); }
void handleUnsupportedContent(QNetworkReply *reply, bool requestFileName = false);
void cleanup();
private Q_SLOTS:
void save() const;
void updateRow();
private:
void addItem(DownloadItem *item);
void updateItemCount();
void load();
AutoSaver *m_autoSaver;
DownloadModel *m_model;
QNetworkAccessManager *m_manager;
QFileIconProvider *m_iconProvider;
QList<DownloadItem*> m_downloads;
RemovePolicy m_removePolicy;
friend class DownloadModel;
private:
Ui_DownloadManager* ui;
static DownloadManager* self;
};
class DownloadModel : public QAbstractListModel
{
friend class DownloadManager;
Q_OBJECT
public:
DownloadModel(DownloadManager *downloadManager, QObject *parent = 0);
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
private:
DownloadManager *m_downloadManager;
};
} // namespace Dialog
} // namespace Gui
#endif // GUI_DIALOG_DOWNLOADMANAGER_H

View File

@ -0,0 +1,83 @@
<ui version="4.0" >
<class>Gui::Dialog::DownloadManager</class>
<widget class="QDialog" name="Gui::Dialog::DownloadManager" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>332</width>
<height>252</height>
</rect>
</property>
<property name="windowTitle" >
<string>Downloads</string>
</property>
<layout class="QGridLayout" name="gridLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>0</number>
</property>
<item row="0" column="0" colspan="3" >
<widget class="EditTableView" name="downloadsView" />
</item>
<item row="1" column="0" >
<layout class="QHBoxLayout" name="horizontalLayout" >
<item>
<widget class="QPushButton" name="cleanupButton" >
<property name="enabled" >
<bool>false</bool>
</property>
<property name="text" >
<string>Clean up</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0" >
<size>
<width>58</width>
<height>24</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="1" column="1" >
<widget class="QLabel" name="itemCount" >
<property name="text" >
<string>0 Items</string>
</property>
</widget>
</item>
<item row="1" column="2" >
<spacer name="horizontalSpacer" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0" >
<size>
<width>148</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>EditTableView</class>
<extends>QTableView</extends>
<header>DownloadItem.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,336 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="48.000000px"
height="48.000000px"
id="svg6361"
sodipodi:version="0.32"
inkscape:version="0.46"
sodipodi:docbase="/home/jimmac/gfx/ximian/tango-icon-theme/scalable/actions"
sodipodi:docname="process-stop.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape">
<defs
id="defs3">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 24 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="48 : 24 : 1"
inkscape:persp3d-origin="24 : 16 : 1"
id="perspective52" />
<linearGradient
id="linearGradient2256">
<stop
style="stop-color:#ff0202;stop-opacity:1;"
offset="0"
id="stop2258" />
<stop
style="stop-color:#ff9b9b;stop-opacity:1;"
offset="1"
id="stop2260" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient2248">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop2250" />
<stop
style="stop-color:#ffffff;stop-opacity:0;"
offset="1"
id="stop2252" />
</linearGradient>
<linearGradient
id="linearGradient9647">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop9649" />
<stop
style="stop-color:#dbdbdb;stop-opacity:1;"
offset="1"
id="stop9651" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient21644">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop21646" />
<stop
style="stop-color:#000000;stop-opacity:0;"
offset="1"
id="stop21648" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient21644"
id="radialGradient21650"
cx="25.125"
cy="36.75"
fx="25.125"
fy="36.75"
r="15.75"
gradientTransform="matrix(1.000000,0.000000,0.000000,0.595238,-2.300678e-15,14.87500)"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
id="linearGradient7895">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop7897" />
<stop
style="stop-color:#ffffff;stop-opacity:0;"
offset="1"
id="stop7899" />
</linearGradient>
<linearGradient
id="linearGradient4981">
<stop
style="stop-color:#cc0000;stop-opacity:1;"
offset="0"
id="stop4983" />
<stop
style="stop-color:#b30000;stop-opacity:1.0000000;"
offset="1.0000000"
id="stop4985" />
</linearGradient>
<linearGradient
id="linearGradient15762"
inkscape:collect="always">
<stop
id="stop15764"
offset="0"
style="stop-color:#ffffff;stop-opacity:1;" />
<stop
id="stop15766"
offset="1"
style="stop-color:#ffffff;stop-opacity:0;" />
</linearGradient>
<linearGradient
id="linearGradient14236">
<stop
id="stop14238"
offset="0.0000000"
style="stop-color:#ed4040;stop-opacity:1.0000000;" />
<stop
id="stop14240"
offset="1.0000000"
style="stop-color:#a40000;stop-opacity:1.0000000;" />
</linearGradient>
<linearGradient
id="linearGradient11780">
<stop
style="stop-color:#ff8b8b;stop-opacity:1.0000000;"
offset="0.0000000"
id="stop11782" />
<stop
style="stop-color:#ec1b1b;stop-opacity:1.0000000;"
offset="1.0000000"
id="stop11784" />
</linearGradient>
<linearGradient
id="linearGradient11014">
<stop
style="stop-color:#a80000;stop-opacity:1.0000000;"
offset="0.0000000"
id="stop11016" />
<stop
style="stop-color:#c60000;stop-opacity:1.0000000;"
offset="0.0000000"
id="stop13245" />
<stop
style="stop-color:#e50000;stop-opacity:1.0000000;"
offset="1.0000000"
id="stop11018" />
</linearGradient>
<linearGradient
y2="9.6507530"
x2="9.8940229"
y1="5.3855424"
x1="5.7365270"
gradientTransform="matrix(-1.000000,0.000000,0.000000,-1.000000,31.72170,31.29079)"
gradientUnits="userSpaceOnUse"
id="linearGradient15772"
xlink:href="#linearGradient15762"
inkscape:collect="always" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient11780"
id="linearGradient2057"
x1="15.737001"
y1="12.503600"
x2="53.570126"
y2="47.374317"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(0.000000,-2.000000)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4981"
id="linearGradient4987"
x1="23.995985"
y1="20.105337"
x2="41.047836"
y2="37.959785"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(0.000000,-2.000000)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient7895"
id="linearGradient7901"
x1="15.578875"
y1="16.285088"
x2="32.166405"
y2="28.394291"
gradientUnits="userSpaceOnUse" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient9647"
id="radialGradient2239"
cx="24.30225"
cy="33.30225"
fx="24.30225"
fy="33.30225"
r="12.30225"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.693981,-5.775714e-16,5.775714e-16,1.693981,-16.86529,-25.11111)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4981"
id="linearGradient2243"
gradientUnits="userSpaceOnUse"
x1="23.995985"
y1="20.105337"
x2="41.047836"
y2="37.959785"
gradientTransform="matrix(0.988373,0.000000,0.000000,0.988373,0.279002,0.278984)" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient2248"
id="radialGradient2254"
cx="16.75"
cy="10.666344"
fx="16.75"
fy="10.666344"
r="21.25"
gradientTransform="matrix(4.154957,-2.979206e-24,3.255657e-24,3.198723,-52.84553,-23.50921)"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2256"
id="linearGradient2262"
x1="21.75"
y1="15.80225"
x2="24.30225"
y2="35.05225"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(0.000000,-2.000000)" />
</defs>
<sodipodi:namedview
inkscape:guide-bbox="true"
showguides="true"
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="0.15294118"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="4"
inkscape:cx="0.007276"
inkscape:cy="7.0544576"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:grid-bbox="true"
inkscape:document-units="px"
inkscape:window-width="786"
inkscape:window-height="688"
inkscape:window-x="488"
inkscape:window-y="160"
inkscape:showpageshadow="false" />
<metadata
id="metadata4">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>Stop</dc:title>
<dc:date>2005-10-16</dc:date>
<dc:creator>
<cc:Agent>
<dc:title>Andreas Nilsson</dc:title>
</cc:Agent>
</dc:creator>
<dc:subject>
<rdf:Bag>
<rdf:li>stop</rdf:li>
<rdf:li>halt</rdf:li>
<rdf:li>error</rdf:li>
</rdf:Bag>
</dc:subject>
<cc:license
rdf:resource="http://creativecommons.org/licenses/publicdomain/" />
<dc:contributor>
<cc:Agent>
<dc:title>Jakub Steiner</dc:title>
</cc:Agent>
</dc:contributor>
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/publicdomain/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
</cc:License>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<path
sodipodi:type="arc"
style="opacity:0.63068183;color:#000000;fill:url(#radialGradient21650);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
id="path21642"
sodipodi:cx="25.125"
sodipodi:cy="36.75"
sodipodi:rx="15.75"
sodipodi:ry="9.375"
d="M 40.875 36.75 A 15.75 9.375 0 1 1 9.375,36.75 A 15.75 9.375 0 1 1 40.875 36.75 z"
transform="matrix(1.173803,0.000000,0.000000,0.600000,-5.265866,19.57500)" />
<path
style="fill:url(#linearGradient4987);fill-opacity:1;fill-rule:evenodd;stroke:#860000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 15.591006,0.4919213 L 32.676311,0.4919213 L 45.497585,13.586385 L 45.497585,31.48003 L 32.848986,43.496929 L 15.418649,43.496929 L 2.4943857,30.658264 L 2.4943857,13.464078 L 15.591006,0.4919213 z "
id="path9480"
sodipodi:nodetypes="ccccccccc" />
<path
style="opacity:0.81318683;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient2057);stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1"
d="M 16.020655,1.5003424 L 32.248563,1.5003424 L 44.496456,13.922717 L 44.496456,31.037001 L 32.638472,42.48783 L 15.870253,42.48783 L 3.5090792,30.208718 L 3.5090792,13.84561 L 16.020655,1.5003424 z "
id="path9482"
sodipodi:nodetypes="ccccccccc" />
<path
style="opacity:0.28977272;fill:url(#radialGradient2254);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 15.6875,0.75 L 2.75,13.5625 L 2.75,30.5625 L 5.6875,33.46875 C 22.450041,33.526299 22.164665,20.450067 45.25,21.59375 L 45.25,13.6875 L 32.5625,0.75 L 15.6875,0.75 z "
id="path2241"
sodipodi:nodetypes="cccccccc" />
<path
style="fill:url(#radialGradient2239);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient2262);stroke-width:0.99999958;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 16.767175,10.5 L 12.5,14.767175 L 20.035075,22.30225 L 12.5,29.837325 L 16.767175,34.104501 L 24.30225,26.569425 L 31.837325,34.104501 L 36.104501,29.837325 L 28.569425,22.30225 L 36.104501,14.767175 L 31.837325,10.5 L 24.30225,18.035075 L 16.767175,10.5 z "
id="path2787" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -49,6 +49,7 @@
<file>edit-edit.svg</file>
<file>help-browser.svg</file>
<file>preferences-system.svg</file>
<file>process-stop.svg</file>
<file>window-new.svg</file>
<file>camera-photo.svg</file>
<file>applications-accessories.svg</file>

View File

@ -64,6 +64,8 @@
#include "MainWindow.h"
#include "Application.h"
#include "Assistant.h"
#include "DownloadDialog.h"
#include "DownloadManager.h"
#include "WaitCursor.h"
#include "Action.h"
@ -1543,6 +1545,12 @@ void MainWindow::loadUrls(App::Document* doc, const QList<QUrl>& url)
(const char*)info.absoluteFilePath().toUtf8());
}
}
else if (it->scheme().toLower() == QLatin1String("http")) {
Gui::Dialog::DownloadManager::getInstance()->download(*it);
}
else if (it->scheme().toLower() == QLatin1String("ftp")) {
Gui::Dialog::DownloadManager::getInstance()->download(*it);
}
}
const char *docName = doc ? doc->getName() : "Unnamed";

View File

@ -56,6 +56,7 @@
#include <Gui/DownloadDialog.h>
#include <Gui/Command.h>
#include <Gui/OnlineDocumentation.h>
#include <Gui/DownloadManager.h>
#include <Base/Parameter.h>
#include <Base/Exception.h>
@ -119,6 +120,8 @@ BrowserView::BrowserView(QWidget* parent)
this, SLOT(onLinkClicked(const QUrl &)));
connect(view->page(), SIGNAL(downloadRequested(const QNetworkRequest &)),
this, SLOT(onDownloadRequested(const QNetworkRequest &)));
connect(view->page(), SIGNAL(unsupportedContent(QNetworkReply*)),
this, SLOT(onUnsupportedContent(QNetworkReply*)));
}
/** Destroys the object and frees any allocated resources */
@ -181,8 +184,12 @@ bool BrowserView::chckHostAllowed(const QString& host)
void BrowserView::onDownloadRequested(const QNetworkRequest & request)
{
Dialog::DownloadDialog dlg (request.url(),this);
dlg.exec();
Gui::Dialog::DownloadManager::getInstance()->download(request);
}
void BrowserView::onUnsupportedContent(QNetworkReply* reply)
{
Gui::Dialog::DownloadManager::getInstance()->handleUnsupportedContent(reply);
}
void BrowserView::load(const char* URL)

View File

@ -96,6 +96,7 @@ protected Q_SLOTS:
void onLinkClicked (const QUrl& url);
bool chckHostAllowed(const QString& host);
void onDownloadRequested(const QNetworkRequest& request);
void onUnsupportedContent(QNetworkReply* reply);
private:
WebView* view;