summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README3
-rw-r--r--dist/config/config.xml4
-rw-r--r--dist/packages/org.qtproject.ifw.binaries/meta/package.xml2
-rw-r--r--dist/packages/org.qtproject.ifw/meta/package.xml2
-rw-r--r--doc/installerfw.qdoc7
-rw-r--r--examples/openreadme/README6
-rw-r--r--examples/openreadme/config/config.xml9
-rw-r--r--examples/openreadme/packages/or.qtproject.ifw.example.openreadme/data/README.txt3
-rw-r--r--examples/openreadme/packages/or.qtproject.ifw.example.openreadme/meta/installscript.qs77
-rw-r--r--examples/openreadme/packages/or.qtproject.ifw.example.openreadme/meta/package.xml11
-rw-r--r--examples/openreadme/packages/or.qtproject.ifw.example.openreadme/meta/readmecheckboxform.ui34
-rw-r--r--installerfw.pri3
-rw-r--r--src/libs/installer/abstractfiletask.cpp117
-rw-r--r--src/libs/installer/abstractfiletask.h156
-rw-r--r--src/libs/installer/abstracttask.h79
-rw-r--r--src/libs/installer/adminauthorization_x11.cpp10
-rw-r--r--src/libs/installer/constants.h2
-rw-r--r--src/libs/installer/copyfiletask.cpp130
-rw-r--r--src/libs/installer/copyfiletask.h66
-rw-r--r--src/libs/installer/downloadfiletask.cpp388
-rw-r--r--src/libs/installer/downloadfiletask.h95
-rw-r--r--src/libs/installer/downloadfiletask_p.h113
-rw-r--r--src/libs/installer/getrepositoriesmetainfojob.cpp205
-rw-r--r--src/libs/installer/getrepositorymetainfojob.cpp168
-rw-r--r--src/libs/installer/getrepositorymetainfojob.h127
-rw-r--r--src/libs/installer/init.cpp3
-rw-r--r--src/libs/installer/installer.pro24
-rw-r--r--src/libs/installer/link.cpp2
-rw-r--r--src/libs/installer/metadatajob.cpp380
-rw-r--r--src/libs/installer/metadatajob.h (renamed from src/libs/installer/getrepositoriesmetainfojob.h)82
-rw-r--r--src/libs/installer/metadatajob_p.h120
-rw-r--r--src/libs/installer/observer.cpp191
-rw-r--r--src/libs/installer/observer.h105
-rw-r--r--src/libs/installer/packagemanagercore.cpp22
-rw-r--r--src/libs/installer/packagemanagercore.h1
-rw-r--r--src/libs/installer/packagemanagercore_p.cpp47
-rw-r--r--src/libs/installer/packagemanagercore_p.h8
-rw-r--r--src/libs/installer/packagemanagergui.cpp77
-rw-r--r--src/libs/installer/packagemanagergui.h5
-rw-r--r--src/libs/installer/runextensions.h435
-rw-r--r--src/libs/installer/settings.cpp12
-rw-r--r--src/libs/installer/settings.h2
-rw-r--r--src/libs/installer/unziptask.cpp304
-rw-r--r--src/libs/installer/unziptask.h70
-rw-r--r--src/libs/kdtools/kdsavefile.cpp13
-rw-r--r--src/libs/kdtools/kdsysinfo.cpp2
-rw-r--r--src/libs/kdtools/kdupdaterupdatesourcesinfo.cpp2
-rw-r--r--src/sdk/installerbasecommons.cpp29
-rw-r--r--src/sdk/installerbasecommons.h1
-rw-r--r--src/sdk/sdk.pro6
-rw-r--r--src/sdk/settingsdialog.h8
-rw-r--r--tests/auto/installer/installer.pro3
-rw-r--r--tests/auto/installer/settings/data/full_config.xml1
-rw-r--r--tests/auto/installer/task/task.pro8
-rw-r--r--tests/auto/installer/task/tst_task.cpp131
-rwxr-xr-x[-rw-r--r--]tools/build_installer.py0
-rw-r--r--tools/common/repositorygen.cpp10
-rw-r--r--tools/getrepositorycontent/main.cpp19
58 files changed, 3360 insertions, 580 deletions
diff --git a/README b/README
index d9c9be7d4..7cc4340ac 100644
--- a/README
+++ b/README
@@ -15,7 +15,8 @@ Notes
- To build an installer, it is advised to use a statically linked Qt. See the
documentation at
http://doc-snapshot.qt-project.org/qtifw-master/ifw-getting-started.html
-- At the moment, only building with Qt 4.8.x is supported.
+- At the moment, building with Qt 4.8.x and Qt 5.2.x is supported.
+- Qt IFW 2.0 and on will only support building with Qt 5.
Getting Help
diff --git a/dist/config/config.xml b/dist/config/config.xml
index 1397f6b3c..c8eb42458 100644
--- a/dist/config/config.xml
+++ b/dist/config/config.xml
@@ -1,7 +1,7 @@
<?xml version="1.0"?>
<Installer>
<Name>Qt Installer Framework</Name>
- <Title>Qt Installer Framework 1.5.1</Title>
+ <Title>Qt Installer Framework 1.5.81</Title>
<Version>1.0.0</Version>
<Publisher>Qt Project</Publisher>
<ProductUrl>http://qt-project.org</ProductUrl>
@@ -9,5 +9,5 @@
<UninstallerName>Uninstaller</UninstallerName>
<!-- Tweaked for windows in installscript.qs -->
- <TargetDir>@homeDir@/Qt/QtIFW-1.5.1</TargetDir>
+ <TargetDir>@homeDir@/Qt/QtIFW-1.5.81</TargetDir>
</Installer>
diff --git a/dist/packages/org.qtproject.ifw.binaries/meta/package.xml b/dist/packages/org.qtproject.ifw.binaries/meta/package.xml
index 9e0116816..cca6d04f0 100644
--- a/dist/packages/org.qtproject.ifw.binaries/meta/package.xml
+++ b/dist/packages/org.qtproject.ifw.binaries/meta/package.xml
@@ -2,7 +2,7 @@
<Package>
<DisplayName>Qt Installer Framework Binaries</DisplayName>
<Description>Installs the binaries, examples and help files.</Description>
- <Version>1.5.1</Version>
+ <Version>1.5.81</Version>
<ReleaseDate>2013-12-12</ReleaseDate>
<Default>True</Default>
</Package>
diff --git a/dist/packages/org.qtproject.ifw/meta/package.xml b/dist/packages/org.qtproject.ifw/meta/package.xml
index ffd97fb48..1101b318d 100644
--- a/dist/packages/org.qtproject.ifw/meta/package.xml
+++ b/dist/packages/org.qtproject.ifw/meta/package.xml
@@ -2,7 +2,7 @@
<Package>
<DisplayName>Qt Installer Framework</DisplayName>
<Description>Installs the Qt Installer Framework.</Description>
- <Version>1.5.1</Version>
+ <Version>1.5.81</Version>
<ReleaseDate>2013-12-12</ReleaseDate>
<Licenses>
<License name="LGPL 2.1" file="LICENSE.LGPL" />
diff --git a/doc/installerfw.qdoc b/doc/installerfw.qdoc
index 4a85111a5..57b575ee4 100644
--- a/doc/installerfw.qdoc
+++ b/doc/installerfw.qdoc
@@ -204,6 +204,13 @@
\o Background
\o Filename for an image used as \a QWizard::BackgroundPixmap (only used by MacStyle).
\row
+ \o WizardStyle
+ \o Set the wizard style to be used ("Modern", "Mac", "Aero" or "Classic").
+ \row
+ \o TitleColor
+ \o Set the color of the titles and subtitles (takes an HTML color code,
+ such as "#88FF33").
+ \row
\o RunProgram
\o Command executed after the installer is done if the user accepts
the action.
diff --git a/examples/openreadme/README b/examples/openreadme/README
new file mode 100644
index 000000000..43e109350
--- /dev/null
+++ b/examples/openreadme/README
@@ -0,0 +1,6 @@
+Shows how to add a 'Open ReadMe' checkbox to the final page.
+
+Generate installer with
+
+binarycreator --offline-only -c config/config.xml -p packages installer
+
diff --git a/examples/openreadme/config/config.xml b/examples/openreadme/config/config.xml
new file mode 100644
index 000000000..c2ee07b65
--- /dev/null
+++ b/examples/openreadme/config/config.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Installer>
+ <Name>Qt Installer Framework - Open ReadMe Example</Name>
+ <Version>1.0.0</Version>
+ <Title>Qt Installer Framework - Open Readme Example</Title>
+ <Publisher>Qt-Project</Publisher>
+ <StartMenuDir>Qt Installer Framework - 'Open ReadMe' Example</StartMenuDir>
+ <TargetDir>@homeDir@/IFWOpenReadMeExample</TargetDir>
+</Installer>
diff --git a/examples/openreadme/packages/or.qtproject.ifw.example.openreadme/data/README.txt b/examples/openreadme/packages/or.qtproject.ifw.example.openreadme/data/README.txt
new file mode 100644
index 000000000..b419f85a9
--- /dev/null
+++ b/examples/openreadme/packages/or.qtproject.ifw.example.openreadme/data/README.txt
@@ -0,0 +1,3 @@
+README
+
+
diff --git a/examples/openreadme/packages/or.qtproject.ifw.example.openreadme/meta/installscript.qs b/examples/openreadme/packages/or.qtproject.ifw.example.openreadme/meta/installscript.qs
new file mode 100644
index 000000000..f47c3dd8d
--- /dev/null
+++ b/examples/openreadme/packages/or.qtproject.ifw.example.openreadme/meta/installscript.qs
@@ -0,0 +1,77 @@
+/**************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+
+function Component()
+{
+ installer.installationFinished.connect(this, Component.prototype.installationFinishedPageIsShown);
+ installer.finishButtonClicked.connect(this, Component.prototype.installationFinished);
+}
+
+Component.prototype.createOperations = function()
+{
+ component.createOperations();
+}
+
+Component.prototype.installationFinishedPageIsShown = function()
+{
+ try {
+ if (installer.isInstaller() && installer.status == QInstaller.Success) {
+ installer.addWizardPageItem( component, "ReadMeCheckBoxForm", QInstaller.InstallationFinished );
+ }
+ } catch(e) {
+ print(e);
+ }
+}
+
+Component.prototype.installationFinished = function()
+{
+ try {
+ if (installer.isInstaller() && installer.status == QInstaller.Success) {
+ var isReadMeCheckBoxChecked = component.userInterface( "ReadMeCheckBoxForm" ).readMeCheckBox.checked;
+ if (isReadMeCheckBoxChecked) {
+ QDesktopServices.openUrl("file:///" + installer.value("TargetDir") + "/README.txt");
+ }
+ }
+ } catch(e) {
+ print(e);
+ }
+}
+
diff --git a/examples/openreadme/packages/or.qtproject.ifw.example.openreadme/meta/package.xml b/examples/openreadme/packages/or.qtproject.ifw.example.openreadme/meta/package.xml
new file mode 100644
index 000000000..542e97823
--- /dev/null
+++ b/examples/openreadme/packages/or.qtproject.ifw.example.openreadme/meta/package.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Package>
+ <DisplayName>Open readme</DisplayName>
+ <Description>Show checkbox asking whether to open Readme at the end</Description>
+ <ReleaseDate>2013-01-01</ReleaseDate>
+ <Version>1.0.0-1</Version>
+ <Script>installscript.qs</Script>
+ <UserInterfaces>
+ <UserInterface>readmecheckboxform.ui</UserInterface>
+ </UserInterfaces>
+</Package>
diff --git a/examples/openreadme/packages/or.qtproject.ifw.example.openreadme/meta/readmecheckboxform.ui b/examples/openreadme/packages/or.qtproject.ifw.example.openreadme/meta/readmecheckboxform.ui
new file mode 100644
index 000000000..d5fec8a85
--- /dev/null
+++ b/examples/openreadme/packages/or.qtproject.ifw.example.openreadme/meta/readmecheckboxform.ui
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ReadMeCheckBoxForm</class>
+ <widget class="QWidget" name="ReadMeCheckBoxForm">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>412</width>
+ <height>179</height>
+ </rect>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QCheckBox" name="readMeCheckBox">
+ <property name="text">
+ <string>Open ReadMe</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="tristate">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/installerfw.pri b/installerfw.pri
index 28caf4000..6f2ae42ce 100644
--- a/installerfw.pri
+++ b/installerfw.pri
@@ -3,7 +3,7 @@
}
IFW_PRI_INCLUDED = 1
-IFW_VERSION = 1.5.1
+IFW_VERSION = 1.5.81
IFW_REPOSITORY_FORMAT_VERSION = 1.0.0
IFW_NEWLINE = $$escape_expand(\\n\\t)
@@ -105,6 +105,7 @@ isEqual(QT_MAJOR_VERSION, 4) {
QTPLUGIN += qico qtaccessiblewidgets
QT += concurrent network script xml
}
+ CONFIG += no_private_qt_headers_warning
}
CONFIG += depend_includepath
diff --git a/src/libs/installer/abstractfiletask.cpp b/src/libs/installer/abstractfiletask.cpp
new file mode 100644
index 000000000..ce18422a0
--- /dev/null
+++ b/src/libs/installer/abstractfiletask.cpp
@@ -0,0 +1,117 @@
+/**************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+#include "abstractfiletask.h"
+
+namespace QInstaller {
+
+AbstractFileTask::AbstractFileTask()
+{
+ registerMetaTypes();
+}
+
+AbstractFileTask::AbstractFileTask(const QString &source)
+{
+ registerMetaTypes();
+ setTaskItem(FileTaskItem(source));
+}
+
+AbstractFileTask::AbstractFileTask(const FileTaskItem &item)
+{
+ registerMetaTypes();
+ setTaskItem(item);
+}
+
+AbstractFileTask::AbstractFileTask(const QString &source, const QString &target)
+{
+ registerMetaTypes();
+ setTaskItem(FileTaskItem(source, target));
+}
+
+QList<FileTaskItem> AbstractFileTask::taskItems() const
+{
+ QReadLocker _(&m_lock);
+ return m_items;
+}
+
+void AbstractFileTask::setTaskItem(const FileTaskItem &item)
+{
+ clearTaskItems();
+ addTaskItem(item);
+}
+
+
+// -- protected
+
+void AbstractFileTask::clearTaskItems()
+{
+ QWriteLocker _(&m_lock);
+ m_items.clear();
+}
+
+void AbstractFileTask::addTaskItem(const FileTaskItem &item)
+{
+ QWriteLocker _(&m_lock);
+ m_items.append(item);
+}
+
+void AbstractFileTask::setTaskItems(const QList<FileTaskItem> &items)
+{
+ clearTaskItems();
+ addTaskItems(items);
+}
+
+void AbstractFileTask::addTaskItems(const QList<FileTaskItem> &items)
+{
+ QWriteLocker _(&m_lock);
+ m_items.append(items);
+}
+
+
+// -- private
+
+void AbstractFileTask::registerMetaTypes()
+{
+ qRegisterMetaType<QInstaller::FileTaskItem>();
+ qRegisterMetaType<QInstaller::FileTaskResult>();
+ qRegisterMetaType<QInstaller::FileTaskException>();
+}
+
+} // namespace QInstaller
diff --git a/src/libs/installer/abstractfiletask.h b/src/libs/installer/abstractfiletask.h
new file mode 100644
index 000000000..858a35f40
--- /dev/null
+++ b/src/libs/installer/abstractfiletask.h
@@ -0,0 +1,156 @@
+/**************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+
+#ifndef ABSTRACTFILETASK_H
+#define ABSTRACTFILETASK_H
+
+#include "abstracttask.h"
+#include "installer_global.h"
+
+#include <QObject>
+#include <QReadWriteLock>
+
+#if QT_VERSION < 0x050000
+#include <qtconcurrentexception.h>
+#define QException QtConcurrent::Exception
+#define QUnhandledException QtConcurrent::UnhandledException
+#endif
+
+namespace QInstaller {
+
+namespace TaskRole {
+enum
+{
+ Checksum,
+ TaskItem,
+ SourceFile,
+ TargetFile,
+ UserRole = 1000
+};
+}
+
+class FileTaskItem : public AbstractTaskData
+{
+public:
+ FileTaskItem() {}
+ explicit FileTaskItem(const QString &s)
+ {
+ insert(TaskRole::SourceFile, s);
+ }
+ FileTaskItem(const QString &s, const QString &t)
+ {
+ insert(TaskRole::SourceFile, s);
+ insert(TaskRole::TargetFile, t);
+ }
+
+ QString source() const { return value(TaskRole::SourceFile).toString(); }
+ QString target() const { return value(TaskRole::TargetFile).toString(); }
+};
+
+class FileTaskResult : public AbstractTaskData
+{
+public:
+ FileTaskResult() {}
+ FileTaskResult(const QString &t, const QByteArray &c, const FileTaskItem &i)
+ {
+ insert(TaskRole::Checksum, c);
+ insert(TaskRole::TargetFile, t);
+ insert(TaskRole::TaskItem, QVariant::fromValue(i));
+ }
+
+ QString target() const { return value(TaskRole::TargetFile).toString(); }
+ QByteArray checkSum() const { return value(TaskRole::Checksum).toByteArray(); }
+ FileTaskItem taskItem() const { return value(TaskRole::TaskItem).value<FileTaskItem>(); }
+};
+
+class FileTaskException : public QException
+{
+public:
+ FileTaskException() {}
+ ~FileTaskException() throw() {}
+ explicit FileTaskException(const QString &message)
+ : m_message(message) {}
+
+ void raise() const { throw *this; }
+ QString message() const { return m_message; }
+ FileTaskException *clone() const { return new FileTaskException(*this); }
+
+private:
+ QString m_message;
+};
+
+class INSTALLER_EXPORT AbstractFileTask : public AbstractTask<FileTaskResult>
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(AbstractFileTask)
+
+public:
+ AbstractFileTask();
+ virtual ~AbstractFileTask() {}
+
+ explicit AbstractFileTask(const QString &source);
+ explicit AbstractFileTask(const FileTaskItem &item);
+ AbstractFileTask(const QString &source, const QString &target);
+
+ QList<FileTaskItem> taskItems() const;
+ void setTaskItem(const FileTaskItem &item);
+
+protected:
+ void clearTaskItems();
+ void addTaskItem(const FileTaskItem &item);
+ void setTaskItems(const QList<FileTaskItem> &items);
+ void addTaskItems(const QList<FileTaskItem> &items);
+
+private:
+ void registerMetaTypes();
+
+private:
+ QList<FileTaskItem> m_items;
+ mutable QReadWriteLock m_lock;
+};
+
+} // namespace QInstaller
+
+Q_DECLARE_METATYPE(QInstaller::FileTaskItem)
+Q_DECLARE_METATYPE(QInstaller::FileTaskResult)
+Q_DECLARE_METATYPE(QInstaller::FileTaskException)
+
+#endif // ABSTRACTFILETASK_H
diff --git a/src/libs/installer/abstracttask.h b/src/libs/installer/abstracttask.h
new file mode 100644
index 000000000..2f458a4c2
--- /dev/null
+++ b/src/libs/installer/abstracttask.h
@@ -0,0 +1,79 @@
+/**************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+
+#ifndef ABSTRACTTASK_H
+#define ABSTRACTTASK_H
+
+#include "runextensions.h"
+
+#include <QFutureInterface>
+
+namespace QInstaller {
+
+class AbstractTaskData
+{
+public:
+ AbstractTaskData() {}
+ virtual ~AbstractTaskData() = 0;
+
+ QVariant value(int role) const { return m_data.value(role); }
+ void insert(int key, const QVariant &value) { m_data.insert(key, value); }
+
+private:
+ QHash<int, QVariant> m_data;
+};
+inline AbstractTaskData::~AbstractTaskData() {}
+
+template <typename T>
+class AbstractTask : public QObject
+{
+ Q_DISABLE_COPY(AbstractTask)
+
+public:
+ AbstractTask() {}
+ virtual ~AbstractTask() {}
+
+ virtual void doTask(QFutureInterface<T> &futureInterface) = 0;
+};
+
+} // namespace QInstaller
+
+#endif // ABSTRACTTASK_H
diff --git a/src/libs/installer/adminauthorization_x11.cpp b/src/libs/installer/adminauthorization_x11.cpp
index 9cce8a08b..92567050a 100644
--- a/src/libs/installer/adminauthorization_x11.cpp
+++ b/src/libs/installer/adminauthorization_x11.cpp
@@ -208,11 +208,11 @@ bool AdminAuthorization::execute(QWidget *parent, const QString &program, const
::write(masterFD, pwd.data(), pwd.length());
::write(masterFD, "\n", 1);
::read(masterFD, buf, pwd.length() + 1);
- }
+ }
}
if (bytes == 0)
::usleep(100000);
- }
+ }
if (!errData.isEmpty()) {
printError(parent, QString::fromLocal8Bit(errData.constData()));
return false;
@@ -225,9 +225,9 @@ bool AdminAuthorization::execute(QWidget *parent, const QString &program, const
::close(pipedData[1]);
if (exited)
return exitStatus == 0;
-
+
return false;
- }
+ }
// child process
else {
@@ -236,7 +236,7 @@ bool AdminAuthorization::execute(QWidget *parent, const QString &program, const
for (int sig = 1; sig < NSIG; ++sig)
signal(sig, SIG_DFL);
signal(SIGHUP, SIG_IGN);
-
+
::setsid();
::ioctl(slaveFD, TIOCSCTTY, 1);
diff --git a/src/libs/installer/constants.h b/src/libs/installer/constants.h
index 7ea73bbb9..d537555fb 100644
--- a/src/libs/installer/constants.h
+++ b/src/libs/installer/constants.h
@@ -88,6 +88,8 @@ static const QLatin1String scTargetConfigurationFile("TargetConfigurationFile");
static const QLatin1String scAllowNonAsciiCharacters("AllowNonAsciiCharacters");
static const QLatin1String scRepositorySettingsPageVisible("RepositorySettingsPageVisible");
static const QLatin1String scAllowSpaceInPath("AllowSpaceInPath");
+static const QLatin1String scWizardStyle("WizardStyle");
+static const QLatin1String scTitleColor("TitleColor");
}
#endif // CONSTANTS_H
diff --git a/src/libs/installer/copyfiletask.cpp b/src/libs/installer/copyfiletask.cpp
new file mode 100644
index 000000000..4fe2a17ac
--- /dev/null
+++ b/src/libs/installer/copyfiletask.cpp
@@ -0,0 +1,130 @@
+/**************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+#include "copyfiletask.h"
+#include "observer.h"
+
+#include <QFileInfo>
+#include <QTemporaryFile>
+
+namespace QInstaller {
+
+CopyFileTask::CopyFileTask(const FileTaskItem &item)
+ : AbstractFileTask(item)
+{
+}
+
+CopyFileTask::CopyFileTask(const QString &source)
+ : AbstractFileTask(source)
+{
+}
+
+CopyFileTask::CopyFileTask(const QString &source, const QString &target)
+ : AbstractFileTask(source, target)
+{
+}
+
+void CopyFileTask::doTask(QFutureInterface<FileTaskResult> &fi)
+{
+ fi.reportStarted();
+ fi.setExpectedResultCount(1);
+
+ if (taskItems().isEmpty()) {
+ fi.reportException(FileTaskException(QLatin1String("Invalid task item count.")));
+ fi.reportFinished(); return; // error
+ }
+
+ const FileTaskItem item = taskItems().first();
+ FileTaskObserver observer(QCryptographicHash::Sha1);
+
+ QFile source(item.source());
+ if (!source.open(QIODevice::ReadOnly)) {
+ fi.reportException(FileTaskException(QString::fromLatin1("Could not open source '%1' "
+ "for read. Error: %2.").arg(source.fileName(), source.errorString())));
+ fi.reportFinished(); return; // error
+ }
+ observer.setBytesToTransfer(source.size());
+
+ QScopedPointer<QFile> file;
+ const QString target = item.target();
+ if (target.isEmpty()) {
+ QTemporaryFile *tmp = new QTemporaryFile;
+ tmp->setAutoRemove(false);
+ file.reset(tmp);
+ } else {
+ file.reset(new QFile(target));
+ }
+ if (!file->open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ fi.reportException(FileTaskException(QString::fromLatin1("Could not open target '%1' "
+ "for write. Error: %2.").arg(file->fileName(), file->errorString())));
+ fi.reportFinished(); return; // error
+ }
+
+ QByteArray buffer(32768, Qt::Uninitialized);
+ while (!source.atEnd() && source.error() == QFile::NoError) {
+ if (fi.isCanceled())
+ break;
+ if (fi.isPaused())
+ fi.waitForResume();
+
+ const qint64 read = source.read(buffer.data(), buffer.size());
+ qint64 written = 0;
+ while (written < read) {
+ const qint64 toWrite = file->write(buffer.constData() + written, read - written);
+ if (toWrite < 0) {
+ fi.reportException(FileTaskException(QString::fromLatin1("Writing to target "
+ "'%1' failed. Error: %2.").arg(file->fileName(), file->errorString())));
+ }
+ written += toWrite;
+ }
+
+ observer.addSample(read);
+ observer.timerEvent(NULL);
+ observer.addBytesTransfered(read);
+ observer.addCheckSumData(buffer.data(), read);
+
+ fi.setProgressValueAndText(observer.progressValue(), observer.progressText());
+ }
+
+ fi.reportResult(FileTaskResult(file->fileName(), observer.checkSum(), item), 0);
+ fi.reportFinished();
+}
+
+} // namespace QInstaller
diff --git a/src/libs/installer/copyfiletask.h b/src/libs/installer/copyfiletask.h
new file mode 100644
index 000000000..d9cc20f93
--- /dev/null
+++ b/src/libs/installer/copyfiletask.h
@@ -0,0 +1,66 @@
+/**************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+
+#ifndef COPYFILETASK_H
+#define COPYFILETASK_H
+
+#include "abstractfiletask.h"
+
+namespace QInstaller {
+
+class INSTALLER_EXPORT CopyFileTask : public AbstractFileTask
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(CopyFileTask)
+
+public:
+ CopyFileTask() {}
+ explicit CopyFileTask(const FileTaskItem &item);
+
+ explicit CopyFileTask(const QString &source);
+ CopyFileTask(const QString &source, const QString &target);
+
+ void doTask(QFutureInterface<FileTaskResult> &fi);
+};
+
+} // namespace QInstaller
+
+#endif // COPYFILETASK_H
diff --git a/src/libs/installer/downloadfiletask.cpp b/src/libs/installer/downloadfiletask.cpp
new file mode 100644
index 000000000..8d15a835d
--- /dev/null
+++ b/src/libs/installer/downloadfiletask.cpp
@@ -0,0 +1,388 @@
+/**************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+#include "downloadfiletask.h"
+
+#include "downloadfiletask_p.h"
+#include "observer.h"
+
+#include <QEventLoop>
+#include <QFile>
+#include <QNetworkProxyFactory>
+#include <QSslError>
+#include <QTemporaryFile>
+#include <QTimer>
+
+namespace QInstaller {
+
+Downloader::Downloader()
+ : m_finished(0)
+{
+ connect(&m_nam, SIGNAL(finished(QNetworkReply*)), SLOT(onFinished(QNetworkReply*)));
+}
+
+Downloader::~Downloader()
+{
+ m_nam.disconnect();
+ foreach (QNetworkReply *const reply, m_downloads.keys()) {
+ reply->disconnect();
+ reply->abort();
+ reply->deleteLater();
+ }
+
+ foreach (const Data &data, m_downloads.values()) {
+ data.file->close();
+ delete data.file;
+ delete data.observer;
+ }
+}
+
+void Downloader::download(QFutureInterface<FileTaskResult> &fi, const QList<FileTaskItem> &items,
+ QNetworkProxyFactory *networkProxyFactory)
+{
+ m_items = items;
+ m_futureInterface = &fi;
+
+ fi.reportStarted();
+ fi.setExpectedResultCount(items.count());
+
+ m_nam.setProxyFactory(networkProxyFactory);
+ connect(&m_nam, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)), this,
+ SLOT(onAuthenticationRequired(QNetworkReply*, QAuthenticator*)));
+ QTimer::singleShot(0, this, SLOT(doDownload()));
+}
+
+void Downloader::doDownload()
+{
+ foreach (const FileTaskItem &item, m_items) {
+ if (!startDownload(item))
+ break;
+ }
+
+ if (m_items.isEmpty() || m_futureInterface->isCanceled()) {
+ m_futureInterface->reportFinished();
+ emit finished(); // emit finished, so the event loop can shutdown
+ }
+}
+
+
+// -- private slots
+
+void Downloader::onReadyRead()
+{
+ if (testCanceled()) {
+ m_futureInterface->reportFinished();
+ emit finished(); return; // error
+ }
+
+ QNetworkReply *const reply = qobject_cast<QNetworkReply *>(sender());
+ if (!reply)
+ return;
+
+ const Data &data = m_downloads[reply];
+ if (!data.file->isOpen()) {
+ m_futureInterface->reportException(FileTaskException(QString::fromLatin1("Target '%1' not "
+ "open for write. Error: %2.").arg(data.file->fileName(), data.file->errorString())));
+ return;
+ }
+
+ QByteArray buffer(32768, Qt::Uninitialized);
+ while (reply->bytesAvailable()) {
+ if (testCanceled()) {
+ m_futureInterface->reportFinished();
+ emit finished(); return; // error
+ }
+
+ const qint64 read = reply->read(buffer.data(), buffer.size());
+ qint64 written = 0;
+ while (written < read) {
+ const qint64 toWrite = data.file->write(buffer.constData() + written, read - written);
+ if (toWrite < 0) {
+ m_futureInterface->reportException(FileTaskException(QString::fromLatin1("Writing "
+ "to target '%1' failed. Error: %2.").arg(data.file->fileName(),
+ data.file->errorString())));
+ return;
+ }
+ written += toWrite;
+ }
+
+ data.observer->addSample(read);
+ data.observer->addBytesTransfered(read);
+ data.observer->addCheckSumData(buffer.data(), read);
+
+ int progress = m_finished * 100;
+ foreach (const Data &data, m_downloads.values())
+ progress += data.observer->progressValue();
+ if (!reply->attribute(QNetworkRequest::RedirectionTargetAttribute).isValid()) {
+ m_futureInterface->setProgressValueAndText(progress / m_items.count(),
+ data.observer->progressText());
+ }
+ }
+}
+
+void Downloader::onFinished(QNetworkReply *reply)
+{
+ const Data &data = m_downloads[reply];
+ const QString filename = data.file->fileName();
+ if (!m_futureInterface->isCanceled()) {
+ if (reply->attribute(QNetworkRequest::RedirectionTargetAttribute).isValid()) {
+ const QUrl url = reply->url()
+ .resolved(reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl());
+ const QList<QUrl> redirects = m_redirects.values(reply);
+ if (!redirects.contains(url)) {
+ data.file->close();
+ data.file->remove();
+ delete data.file;
+ delete data.observer;
+
+ FileTaskItem taskItem = data.taskItem;
+ taskItem.insert(TaskRole::SourceFile, url.toString());
+ QNetworkReply *const redirectReply = startDownload(taskItem);
+
+ foreach (const QUrl &redirect, redirects)
+ m_redirects.insertMulti(redirectReply, redirect);
+ m_redirects.insertMulti(redirectReply, url);
+
+ m_downloads.remove(reply);
+ m_redirects.remove(reply);
+ reply->deleteLater();
+ return;
+ } else {
+ m_futureInterface->reportException(FileTaskException(QString::fromLatin1("Redirect"
+ " loop detected '%1'.").arg(url.toString())));
+ return;
+ }
+ }
+ }
+
+ const QByteArray ba = reply->readAll();
+ if (!ba.isEmpty()) {
+ data.observer->addSample(ba.size());
+ data.observer->addBytesTransfered(ba.size());
+ data.observer->addCheckSumData(ba.data(), ba.size());
+ }
+
+ const QByteArray expectedCheckSum = data.taskItem.value(TaskRole::Checksum).toByteArray();
+ if (!expectedCheckSum.isEmpty()) {
+ if (expectedCheckSum != data.observer->checkSum().toHex()) {
+ m_futureInterface->reportException(FileTaskException(QString::fromLatin1("Checksum"
+ " mismatch detected '%1'.").arg(reply->url().toString())));
+ }
+ }
+ m_futureInterface->reportResult(FileTaskResult(filename, data.observer->checkSum(), data.taskItem));
+
+ data.file->close();
+ delete data.file;
+ delete data.observer;
+
+ m_downloads.remove(reply);
+ m_redirects.remove(reply);
+ reply->deleteLater();
+
+ m_finished++;
+ if (m_downloads.isEmpty() || m_futureInterface->isCanceled()) {
+ m_futureInterface->reportFinished();
+ emit finished(); // emit finished, so the event loop can shutdown
+ }
+}
+
+void Downloader::onError(QNetworkReply::NetworkError error)
+{
+ QNetworkReply *const reply = qobject_cast<QNetworkReply *>(sender());
+ if (reply) {
+ const Data &data = m_downloads[reply];
+ m_futureInterface->reportException(FileTaskException(QString::fromLatin1("Network error "
+ "while downloading target '%1'. Error: %2.").arg(data.file->fileName(),
+ reply->errorString())));
+ } else {
+ m_futureInterface->reportException(FileTaskException(QString::fromLatin1("Unknown network "
+ "error while downloading. Error: %1.").arg(error)));
+ }
+}
+
+void Downloader::onSslErrors(const QList<QSslError> &sslErrors)
+{
+#if defined(QT_NO_SSL) || defined(QT_NO_OPENSSL)
+ Q_UNUSED(sslErrors);
+#else
+ foreach (const QSslError &error, sslErrors)
+ qDebug() << QString::fromLatin1("SSL error: %s").arg(error.errorString());
+#endif
+}
+
+void Downloader::onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal)
+{
+ Q_UNUSED(bytesReceived)
+ QNetworkReply *const reply = qobject_cast<QNetworkReply *>(sender());
+ if (reply) {
+ const Data &data = m_downloads[reply];
+ data.observer->setBytesToTransfer(bytesTotal);
+ }
+}
+
+void Downloader::onAuthenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator)
+{
+ if (!authenticator || !reply || !m_downloads.contains(reply))
+ return;
+
+ FileTaskItem *item = &m_downloads[reply].taskItem;
+ const QAuthenticator auth = item->value(TaskRole::Authenticator).value<QAuthenticator>();
+ if (!auth.user().isEmpty()) {
+ authenticator->setUser(auth.user());
+ authenticator->setPassword(auth.password());
+ item->insert(TaskRole::Authenticator, QVariant()); // clear so we fail on next call
+ } else {
+ m_futureInterface->reportException(FileTaskException(QString::fromLatin1("Could not "
+ "authenticate using the provided credentials. Source: '%1'.").arg(reply->url()
+ .toString())));
+ }
+}
+
+
+// -- private
+
+bool Downloader::testCanceled()
+{
+ // TODO: figure out how to implement pause and resume
+ if (m_futureInterface->isPaused()) {
+ m_futureInterface->togglePaused(); // Note: this will trigger cancel
+ m_futureInterface->reportException(FileTaskException(QLatin1String("Pause and resume not "
+ "supported by network transfers.")));
+ }
+ return m_futureInterface->isCanceled();
+}
+
+QNetworkReply *Downloader::startDownload(const FileTaskItem &item)
+{
+ QUrl const source = item.source();
+ if (!source.isValid()) {
+ m_futureInterface->reportException(FileTaskException(QString::fromLatin1("Invalid source "
+ "'%1'. Error: %2.").arg(source.toString(), source.errorString())));
+ return 0;
+ }
+
+ QScopedPointer<QFile> file;
+ const QString target = item.target();
+ if (target.isEmpty()) {
+ QTemporaryFile *tmp = new QTemporaryFile;
+ tmp->setAutoRemove(false);
+ file.reset(tmp);
+ } else {
+ file.reset(new QFile(target));
+ }
+ if (!file->open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ file->remove();
+ m_futureInterface->reportException(FileTaskException(QString::fromLatin1("Could not open "
+ "target '%1' for write. Error: %2.").arg(file->fileName(), file->errorString())));
+ return 0;
+ }
+
+ QNetworkReply *reply = m_nam.get(QNetworkRequest(source));
+ m_downloads.insert(reply, Data(file.take(), new FileTaskObserver(QCryptographicHash::Sha1), item));
+
+ connect(reply, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
+ connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this,
+ SLOT(onError(QNetworkReply::NetworkError)));
+#ifndef QT_NO_OPENSSL
+ // TODO: once we switch to Qt5, use QT_NO_SSL instead of QT_NO_OPENSSL
+ connect(reply, SIGNAL(sslErrors(QList<QSslError>)), SLOT(onSslErrors(QList<QSslError>)));
+#endif
+ connect(reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(onDownloadProgress(qint64,
+ qint64)));
+ return reply;
+}
+
+
+// -- DownloadFileTask
+
+DownloadFileTask::DownloadFileTask(const QList<FileTaskItem> &items)
+ : AbstractFileTask()
+{
+ setTaskItems(items);
+}
+
+void DownloadFileTask::setTaskItem(const FileTaskItem &item)
+{
+ AbstractFileTask::setTaskItem(item);
+}
+
+void DownloadFileTask::addTaskItem(const FileTaskItem &item)
+{
+ AbstractFileTask::addTaskItem(item);
+}
+
+void DownloadFileTask::setTaskItems(const QList<FileTaskItem> &items)
+{
+ AbstractFileTask::setTaskItems(items);
+}
+
+void DownloadFileTask::addTaskItems(const QList<FileTaskItem> &items)
+{
+ AbstractFileTask::addTaskItems(items);
+}
+
+void DownloadFileTask::setAuthenticator(const QAuthenticator &authenticator)
+{
+ m_authenticator = authenticator;
+}
+
+void DownloadFileTask::setProxyFactory(KDUpdater::FileDownloaderProxyFactory *factory)
+{
+ m_proxyFactory.reset(factory);
+}
+
+void DownloadFileTask::doTask(QFutureInterface<FileTaskResult> &fi)
+{
+ QEventLoop el;
+ Downloader downloader;
+ connect(&downloader, SIGNAL(finished()), &el, SLOT(quit()));
+
+ QList<FileTaskItem> items = taskItems();
+ if (!m_authenticator.isNull()) {
+ for (int i = 0; i < items.count(); ++i) {
+ if (items.at(i).value(TaskRole::Authenticator).isNull())
+ items[i].insert(TaskRole::Authenticator, QVariant::fromValue(m_authenticator));
+ }
+ }
+ downloader.download(fi, items, (m_proxyFactory.isNull() ? 0 : m_proxyFactory->clone()));
+ el.exec(); // That's tricky here, we need to run our own event loop to keep QNAM working.
+}
+
+} // namespace QInstaller
diff --git a/src/libs/installer/downloadfiletask.h b/src/libs/installer/downloadfiletask.h
new file mode 100644
index 000000000..c320e6dba
--- /dev/null
+++ b/src/libs/installer/downloadfiletask.h
@@ -0,0 +1,95 @@
+/**************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+
+#ifndef DOWNLOADFILETASK_H
+#define DOWNLOADFILETASK_H
+
+#include "abstractfiletask.h"
+#include "kdupdaterfiledownloaderfactory.h"
+
+#include <QAuthenticator>
+Q_DECLARE_METATYPE(QAuthenticator)
+
+namespace QInstaller {
+
+namespace TaskRole {
+enum
+{
+ Authenticator = TaskRole::TargetFile + 10
+};
+}
+
+class INSTALLER_EXPORT DownloadFileTask : public AbstractFileTask
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(DownloadFileTask)
+
+public:
+ DownloadFileTask() {}
+ explicit DownloadFileTask(const FileTaskItem &item)
+ : AbstractFileTask(item) {}
+ explicit DownloadFileTask(const QList<FileTaskItem> &items);
+
+ explicit DownloadFileTask(const QString &source)
+ : AbstractFileTask(source) {}
+ DownloadFileTask(const QString &source, const QString &target)
+ : AbstractFileTask(source, target) {}
+
+ void addTaskItem(const FileTaskItem &items);
+ void addTaskItems(const QList<FileTaskItem> &items);
+
+ void setTaskItem(const FileTaskItem &items);
+ void setTaskItems(const QList<FileTaskItem> &items);
+
+ void setAuthenticator(const QAuthenticator &authenticator);
+ void setProxyFactory(KDUpdater::FileDownloaderProxyFactory *factory);
+
+ void doTask(QFutureInterface<FileTaskResult> &fi);
+
+private:
+ friend class Downloader;
+ QAuthenticator m_authenticator;
+ QScopedPointer<KDUpdater::FileDownloaderProxyFactory> m_proxyFactory;
+};
+
+} // namespace QInstaller
+
+#endif // DOWNLOADFILETASK_H
diff --git a/src/libs/installer/downloadfiletask_p.h b/src/libs/installer/downloadfiletask_p.h
new file mode 100644
index 000000000..855b32813
--- /dev/null
+++ b/src/libs/installer/downloadfiletask_p.h
@@ -0,0 +1,113 @@
+/**************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+
+#ifndef DOWNLOADFILETASK_P_H
+#define DOWNLOADFILETASK_P_H
+
+#include "downloadfiletask.h"
+
+#include <QNetworkAccessManager>
+#include <QNetworkReply>
+#include <QNetworkRequest>
+
+QT_BEGIN_NAMESPACE
+class QFile;
+class QSslError;
+QT_END_NAMESPACE
+
+namespace QInstaller {
+
+class FileTaskObserver;
+
+struct Data
+{
+ Data()
+ : file(0), observer(0) {}
+ Data(QFile *f, FileTaskObserver *o, const FileTaskItem &fti)
+ : file(f), observer(o), taskItem(fti)
+ {}
+ QFile *file;
+ FileTaskObserver *observer;
+ FileTaskItem taskItem;
+};
+
+class Downloader : public QObject
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(Downloader)
+
+public:
+ Downloader();
+ ~Downloader();
+
+ void download(QFutureInterface<FileTaskResult> &fi, const QList<FileTaskItem> &items,
+ QNetworkProxyFactory *networkProxyFactory);
+
+signals:
+ void finished();
+
+private slots:
+ void doDownload();
+ void onReadyRead();
+ void onFinished(QNetworkReply *reply);
+ void onError(QNetworkReply::NetworkError error);
+ void onSslErrors(const QList<QSslError> &sslErrors);
+ void onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal);
+ void onAuthenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator);
+
+
+private:
+ bool testCanceled();
+ QNetworkReply *startDownload(const FileTaskItem &item);
+
+private:
+ QFutureInterface<FileTaskResult> *m_futureInterface;
+
+ int m_finished;
+ QNetworkAccessManager m_nam;
+ QList<FileTaskItem> m_items;
+ QHash<QNetworkReply*, Data> m_downloads;
+ QMultiHash<QNetworkReply*, QUrl> m_redirects;
+};
+
+} // namespace QInstaller
+
+#endif // DOWNLOADFILETASK_P_H
diff --git a/src/libs/installer/getrepositoriesmetainfojob.cpp b/src/libs/installer/getrepositoriesmetainfojob.cpp
deleted file mode 100644
index cde872064..000000000
--- a/src/libs/installer/getrepositoriesmetainfojob.cpp
+++ /dev/null
@@ -1,205 +0,0 @@
-/**************************************************************************
-**
-** Copyright (C) 2012-2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the Qt Installer Framework.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-**************************************************************************/
-
-#include "getrepositoriesmetainfojob.h"
-
-#include "getrepositorymetainfojob.h"
-#include "productkeycheck.h"
-#include "packagemanagercore_p.h"
-
-#include <QtCore/QDebug>
-
-using namespace KDUpdater;
-using namespace QInstaller;
-
-
-// -- GetRepositoriesMetaInfoJob
-
-GetRepositoriesMetaInfoJob::GetRepositoriesMetaInfoJob(PackageManagerCore *core)
- : KDJob(core)
- , m_canceled(false)
- , m_silentRetries(3)
- , m_haveIgnoredError(false)
- , m_core(core)
-{
- setCapabilities(Cancelable);
-}
-
-QStringList GetRepositoriesMetaInfoJob::temporaryDirectories() const
-{
- return m_repositoryByTemporaryDirectory.keys();
-}
-
-QStringList GetRepositoriesMetaInfoJob::releaseTemporaryDirectories() const
-{
- m_tempDirDeleter.releaseAll();
- return m_repositoryByTemporaryDirectory.keys();
-}
-
-Repository GetRepositoriesMetaInfoJob::repositoryForTemporaryDirectory(const QString &tmpDir) const
-{
- return m_repositoryByTemporaryDirectory.value(tmpDir);
-}
-
-int GetRepositoriesMetaInfoJob::numberOfRetrievedRepositories() const
-{
- return m_repositoryByTemporaryDirectory.size();
-}
-
-int GetRepositoriesMetaInfoJob::silentRetries() const
-{
- return m_silentRetries;
-}
-
-void GetRepositoriesMetaInfoJob::setSilentRetries(int retries)
-{
- m_silentRetries = retries;
-}
-
-void GetRepositoriesMetaInfoJob::reset()
-{
- m_canceled = false;
- m_silentRetries = 3;
- m_errorString.clear();
- m_haveIgnoredError = false;
-
- m_repositories.clear();
- m_tempDirDeleter.releaseAndDeleteAll();
- m_repositoryByTemporaryDirectory.clear();
-
- setError(KDJob::NoError);
- setErrorString(QString());
- setCapabilities(Cancelable);
-}
-
-bool GetRepositoriesMetaInfoJob::isCanceled() const
-{
- return m_canceled;
-}
-
-// -- private Q_SLOTS
-
-void GetRepositoriesMetaInfoJob::doStart()
-{
- if ((m_core->isInstaller() && !m_core->isOfflineOnly()) || (m_core->isUpdater()
- || m_core->isPackageManager())) {
- const ProductKeyCheck *const productKeyCheck = ProductKeyCheck::instance();
- foreach (const Repository &repo, m_core->settings().repositories()) {
- if (repo.isEnabled() && productKeyCheck->isValidRepository(repo))
- m_repositories += repo;
- }
- }
-
- fetchNextRepo();
-}
-
-void GetRepositoriesMetaInfoJob::doCancel()
-{
- m_canceled = true;
- if (m_job)
- m_job->cancel();
-}
-
-void GetRepositoriesMetaInfoJob::fetchNextRepo()
-{
- if (m_job) {
- m_job->deleteLater();
- m_job = 0;
- }
-
- if (m_canceled) {
- emitFinishedWithError(KDJob::Canceled, m_errorString);
- return;
- }
-
- if (m_repositories.isEmpty()) {
- if (m_haveIgnoredError)
- emitFinishedWithError(QInstaller::UserIgnoreError, m_errorString);
- else
- emitFinished();
- return;
- }
-
- m_job = new GetRepositoryMetaInfoJob(m_core, this);
- connect(m_job, SIGNAL(finished(KDJob*)), this, SLOT(jobFinished(KDJob*)));
- connect(m_job, SIGNAL(infoMessage(KDJob*, QString)), this, SIGNAL(infoMessage(KDJob*, QString)));
-
- m_job->setSilentRetries(silentRetries());
- m_job->setRepository(m_repositories.takeLast());
- m_job->start();
-}
-
-void GetRepositoriesMetaInfoJob::jobFinished(KDJob *j)
-{
- const GetRepositoryMetaInfoJob *const job = qobject_cast<const GetRepositoryMetaInfoJob *>(j);
- Q_ASSERT(job);
-
- if (job->error() != KDJob::NoError && !job->temporaryDirectory().isEmpty()) {
- try {
- removeDirectory(job->temporaryDirectory());
- } catch (...) {
- }
- }
-
- if (job->error() == KDJob::Canceled
- || (job->error() >= KDJob::UserDefinedError && job->error() < QInstaller::UserIgnoreError)) {
- emit infoMessage(j, job->errorString());
- qDebug() << job->errorString();
- emitFinishedWithError(job->error(), job->errorString());
- return;
- }
-
- if (job->error() == QInstaller::UserIgnoreError) {
- m_haveIgnoredError = true;
- m_errorString = job->errorString();
- } else {
- const QString &tmpdir = job->releaseTemporaryDirectory();
- job->m_tempDirDeleter.passAndRelease(m_tempDirDeleter, tmpdir);
- m_repositoryByTemporaryDirectory.insert(tmpdir, job->repository());
- }
-
- if (job->error() == QInstaller::RepositoryUpdatesReceived) {
- reset();
- QMetaObject::invokeMethod(this, "doStart", Qt::QueuedConnection);
- } else {
- QMetaObject::invokeMethod(this, "fetchNextRepo", Qt::QueuedConnection);
- }
-}
diff --git a/src/libs/installer/getrepositorymetainfojob.cpp b/src/libs/installer/getrepositorymetainfojob.cpp
index 14bcf26f2..8b6b53484 100644
--- a/src/libs/installer/getrepositorymetainfojob.cpp
+++ b/src/libs/installer/getrepositorymetainfojob.cpp
@@ -53,7 +53,6 @@
#include <QTimer>
-
using namespace KDUpdater;
using namespace QInstaller;
@@ -65,20 +64,13 @@ class GetRepositoryMetaInfoJob::ZipRunnable : public QObject, public QRunnable
Q_OBJECT
public:
- ZipRunnable(const QString &archive, const QString &targetDir, QPointer<FileDownloader> downloader)
+ ZipRunnable(const QString &archive, const QString &targetDir)
: QObject()
, QRunnable()
, m_archive(archive)
, m_targetDir(targetDir)
- , m_downloader(downloader)
{}
- ~ZipRunnable()
- {
- if (m_downloader)
- m_downloader->deleteLater();
- }
-
void run()
{
QFile archive(m_archive);
@@ -107,7 +99,6 @@ Q_SIGNALS:
private:
const QString m_archive;
const QString m_targetDir;
- QPointer<FileDownloader> m_downloader;
};
@@ -119,9 +110,10 @@ GetRepositoryMetaInfoJob::GetRepositoryMetaInfoJob(PackageManagerCore *core, QOb
, m_silentRetries(4)
, m_retriesLeft(m_silentRetries)
, m_downloader(0)
- , m_waitForDone(false)
, m_core(core)
+ , m_watcher(0)
{
+ setTotalAmount(100);
setCapabilities(Cancelable);
}
@@ -154,7 +146,13 @@ void GetRepositoryMetaInfoJob::setSilentRetries(int retries)
void GetRepositoryMetaInfoJob::doStart()
{
+ m_canceled = false;
+ setProcessedAmount(0);
+ m_packageHash.clear();
+ m_packageNames.clear();
+ m_packageVersions.clear();
m_retriesLeft = m_silentRetries;
+
startUpdatesXmlDownload();
}
@@ -163,11 +161,16 @@ void GetRepositoryMetaInfoJob::doCancel()
m_canceled = true;
if (m_downloader)
m_downloader->cancelDownload();
+ if (m_watcher)
+ m_watcher->cancel();
+#if QT_VERSION >= 0x050200
+ m_threadPool.clear();
+#endif
+ m_threadPool.waitForDone();
}
void GetRepositoryMetaInfoJob::finished(int error, const QString &errorString)
{
- m_waitForDone = true;
m_threadPool.waitForDone();
(error > KDJob::NoError) ? emitFinishedWithError(error, errorString) : emitFinished();
}
@@ -384,14 +387,15 @@ void GetRepositoryMetaInfoJob::updatesXmlDownloadFinished()
return;
}
- setTotalAmount(m_packageNames.count() + 1);
setProcessedAmount(1);
emit infoMessage(this, tr("Finished updating component meta information."));
- if (m_packageNames.isEmpty())
+ if (m_packageNames.isEmpty()) {
finished(KDJob::NoError);
- else
- fetchNextMetaInfo();
+ setProcessedAmount(100);
+ } else {
+ downloadMetaInfo();
+ }
}
void GetRepositoryMetaInfoJob::updatesXmlDownloadError(const QString &err)
@@ -417,131 +421,83 @@ void GetRepositoryMetaInfoJob::updatesXmlDownloadError(const QString &err)
// meta data download
-void GetRepositoryMetaInfoJob::fetchNextMetaInfo()
+void GetRepositoryMetaInfoJob::downloadMetaInfo()
{
emit infoMessage(this, tr("Retrieving component information from remote repository..."));
-
if (m_canceled) {
- finished(KDJob::Canceled, m_downloader->errorString());
+ finished(KDJob::Canceled, tr("Meta data download canceled."));
return;
}
- if (m_packageNames.isEmpty() && m_currentPackageName.isEmpty()) {
+ if (m_packageNames.isEmpty()) {
finished(KDJob::NoError);
return;
}
- QString next = m_currentPackageName;
- QString nextVersion = m_currentPackageVersion;
- if (next.isEmpty()) {
- m_retriesLeft = m_silentRetries;
- next = m_packageNames.takeLast();
- nextVersion = m_packageVersions.takeLast();
- }
-
- qDebug() << "fetching metadata of" << next << "in version" << nextVersion;
-
bool online = true;
if (m_repository.url().scheme().isEmpty())
online = false;
+ QList<FileTaskItem> items;
const QString repoUrl = m_repository.url().toString();
- const QUrl url = QString::fromLatin1("%1/%2/%3meta.7z").arg(repoUrl, next,
- online ? nextVersion : QString());
- m_downloader = FileDownloaderFactory::instance().create(url.scheme(), this);
-
- if (!m_downloader) {
- m_currentPackageName.clear();
- m_currentPackageVersion.clear();
- qWarning() << "Scheme not supported:" << m_repository.displayname();
- QMetaObject::invokeMethod(this, "fetchNextMetaInfo", Qt::QueuedConnection);
- return;
+ for (int i = 0; i < m_packageNames.count(); ++i) {
+ items.append(FileTaskItem(QString::fromLatin1("%1/%2/%3meta.7z").arg(repoUrl,
+ m_packageNames.at(i), (online ? m_packageVersions.at(i) : QString()))));
+ items[i].insert(TaskRole::Checksum, m_packageHash.value(i).toLatin1());
}
- m_currentPackageName = next;
- m_currentPackageVersion = nextVersion;
- m_downloader->setUrl(url);
- m_downloader->setAutoRemoveDownloadedFile(true);
-
QAuthenticator auth;
auth.setUser(m_repository.username());
auth.setPassword(m_repository.password());
- m_downloader->setAuthenticator(auth);
- connect(m_downloader, SIGNAL(downloadCanceled()), this, SLOT(metaDownloadCanceled()));
- connect(m_downloader, SIGNAL(downloadCompleted()), this, SLOT(metaDownloadFinished()));
- connect(m_downloader, SIGNAL(downloadAborted(QString)), this, SLOT(metaDownloadError(QString)),
- Qt::QueuedConnection);
- connect(m_downloader, SIGNAL(authenticatorChanged(QAuthenticator)), this,
- SLOT(onAuthenticatorChanged(QAuthenticator)));
+ m_metaDataTask.setTaskItems(items);
+ m_metaDataTask.setAuthenticator(auth);
+ m_metaDataTask.setProxyFactory(m_core->proxyFactory()->clone());
- m_downloader->download();
+ m_watcher = new QFutureWatcher<FileTaskResult>(this);
+ connect(m_watcher, SIGNAL(finished()), this, SLOT(metaInfoDownloadFinished()));
+ connect(m_watcher, SIGNAL(progressValueChanged(int)), this, SLOT(onProgressValueChanged(int)));
+ m_watcher->setFuture(QtConcurrent::run(&DownloadFileTask::doTask, &m_metaDataTask));
}
-void GetRepositoryMetaInfoJob::metaDownloadCanceled()
+void GetRepositoryMetaInfoJob::metaInfoDownloadFinished()
{
- finished(KDJob::Canceled, m_downloader->errorString());
-}
-
-void GetRepositoryMetaInfoJob::metaDownloadFinished()
-{
- const QString fn = m_downloader->downloadedFileName();
- Q_ASSERT(!fn.isEmpty());
-
- QFile arch(fn);
- if (!arch.open(QIODevice::ReadOnly)) {
- finished(QInstaller::ExtractionError, tr("Could not open meta info archive: %1. Error: %2").arg(fn,
- arch.errorString()));
- return;
- }
-
- if (!m_packageHash.isEmpty()) {
- // verify file hash
- const QByteArray expectedFileHash = m_packageHash.back().toLatin1();
- const QByteArray realFileHash = QInstaller::calculateHash(&arch, QCryptographicHash::Sha1).toHex();
- if (expectedFileHash != realFileHash) {
- emit infoMessage(this, tr("The hash of one component does not match the expected one."));
- metaDownloadError(tr("Bad hash."));
- return;
+ QFutureWatcher<FileTaskResult> *task = static_cast<QFutureWatcher<FileTaskResult> *>(sender());
+ try {
+ task->waitForFinished();
+ QFuture<FileTaskResult> future = task->future();
+ if (future.resultCount() > 0) {
+ foreach (const FileTaskResult &result, future.results()) {
+ ZipRunnable *runnable = new ZipRunnable(result.target(), m_temporaryDirectory);
+ connect(runnable, SIGNAL(finished(bool, QString)), this, SLOT(unzipFinished(bool,
+ QString)));
+ m_threadPool.start(runnable);
+ }
}
- m_packageHash.removeLast();
+ finished(KDJob::NoError);
+ } catch (FileTaskException &e) {
+ doCancel();
+ finished(KDJob::Canceled, e.message());
+ } catch (QUnhandledException &e) {
+ doCancel();
+ finished(KDJob::Canceled, QLatin1String(e.what()));
+ } catch (...) {
+ doCancel();
+ finished(KDJob::Canceled, tr("Unknown exception."));
}
- arch.close();
- m_currentPackageName.clear();
-
- ZipRunnable *runnable = new ZipRunnable(fn, m_temporaryDirectory, m_downloader);
- connect(runnable, SIGNAL(finished(bool,QString)), this, SLOT(unzipFinished(bool,QString)));
- m_threadPool.start(runnable);
-
- if (!m_waitForDone)
- fetchNextMetaInfo();
}
-void GetRepositoryMetaInfoJob::metaDownloadError(const QString &err)
+void GetRepositoryMetaInfoJob::onProgressValueChanged(int progress)
{
- if (m_retriesLeft <= 0) {
- const QString msg = tr("Could not download meta information for component: %1. Error: %2")
- .arg(m_currentPackageName, err);
-
- QMessageBox::StandardButtons buttons = QMessageBox::Retry | QMessageBox::Cancel;
- const QMessageBox::StandardButton b =
- MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(),
- QLatin1String("updatesXmlDownloadError"), tr("Download Error"), msg, buttons);
-
- if (b == QMessageBox::Cancel || b == QMessageBox::NoButton) {
- finished(KDJob::Canceled, msg);
- return;
- }
- }
-
- m_retriesLeft--;
- QTimer::singleShot(1500, this, SLOT(fetchNextMetaInfo()));
+ setProcessedAmount(progress + 1);
}
void GetRepositoryMetaInfoJob::unzipFinished(bool ok, const QString &error)
{
- if (!ok)
+ if (!ok) {
+ doCancel();
finished(QInstaller::ExtractionError, error);
+ }
}
bool GetRepositoryMetaInfoJob::updateRepositories(QSet<Repository> *repositories, const QString &username,
diff --git a/src/libs/installer/getrepositorymetainfojob.h b/src/libs/installer/getrepositorymetainfojob.h
deleted file mode 100644
index 803f8b43f..000000000
--- a/src/libs/installer/getrepositorymetainfojob.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/**************************************************************************
-**
-** Copyright (C) 2012-2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the Qt Installer Framework.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-**************************************************************************/
-#ifndef GETREPOSITORYMETAINFOJOB_H
-#define GETREPOSITORYMETAINFOJOB_H
-
-#include "fileutils.h"
-#include "installer_global.h"
-#include "repository.h"
-
-#include "kdjob.h"
-
-#include <QtCore/QPointer>
-#include <QtCore/QString>
-#include <QtCore/QStringList>
-#include <QtCore/QThreadPool>
-
-#include <QAuthenticator>
-
-namespace KDUpdater {
- class FileDownloader;
-}
-
-namespace QInstaller {
-
-class GetRepositoriesMetaInfoJob;
-class PackageManagerCore;
-
-class INSTALLER_EXPORT GetRepositoryMetaInfoJob : public KDJob
-{
- Q_OBJECT
- class ZipRunnable;
- friend class QInstaller::GetRepositoriesMetaInfoJob;
-
-public:
- explicit GetRepositoryMetaInfoJob(PackageManagerCore *core, QObject *parent = 0);
- ~GetRepositoryMetaInfoJob();
-
- Repository repository() const;
- void setRepository(const Repository &r);
-
- int silentRetries() const;
- void setSilentRetries(int retries);
-
- QString temporaryDirectory() const;
- QString releaseTemporaryDirectory() const;
-
-private:
- /* reimp */ void doStart();
- /* reimp */ void doCancel();
- void finished(int error, const QString &errorString = QString());
- bool updateRepositories(QSet<Repository> *repositories, const QString &username,
- const QString &password, const QString &displayname = QString());
-
-private Q_SLOTS:
- void startUpdatesXmlDownload();
- void updatesXmlDownloadCanceled();
- void updatesXmlDownloadFinished();
- void updatesXmlDownloadError(const QString &error);
-
- void fetchNextMetaInfo();
- void metaDownloadCanceled();
- void metaDownloadFinished();
- void metaDownloadError(const QString &error);
-
- void unzipFinished(bool status, const QString &error);
- void onAuthenticatorChanged(const QAuthenticator &authenticator);
-
-private:
- bool m_canceled;
- int m_silentRetries;
- int m_retriesLeft;
- Repository m_repository;
- QStringList m_packageNames;
- QStringList m_packageVersions;
- QStringList m_packageHash;
- QPointer<KDUpdater::FileDownloader> m_downloader;
- QString m_currentPackageName;
- QString m_currentPackageVersion;
- QString m_temporaryDirectory;
- mutable TempDirDeleter m_tempDirDeleter;
-
- bool m_waitForDone;
- QThreadPool m_threadPool;
- PackageManagerCore *m_core;
-};
-
-} // namespace QInstaller
-
-#endif // GETREPOSITORYMETAINFOJOB_H
diff --git a/src/libs/installer/init.cpp b/src/libs/installer/init.cpp
index 12891f0e2..eedae80bd 100644
--- a/src/libs/installer/init.cpp
+++ b/src/libs/installer/init.cpp
@@ -188,6 +188,9 @@ static void messageHandler(QtMsgType type, const char *msg)
#else
void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
+ // suppress warning from QPA minimal plugin
+ if (msg.contains(QLatin1String("This plugin does not support propagateSizeHints")))
+ return;
QByteArray ba = trimAndPrepend(type, msg.toLocal8Bit());
if (type != QtDebugMsg) {
ba += QString(QStringLiteral(" (%1:%2, %3)")).arg(
diff --git a/src/libs/installer/installer.pro b/src/libs/installer/installer.pro
index 149287428..837196c5f 100644
--- a/src/libs/installer/installer.pro
+++ b/src/libs/installer/installer.pro
@@ -70,7 +70,6 @@ HEADERS += packagemanagercore.h \
installiconsoperation.h \
selfrestartoperation.h \
settings.h \
- getrepositorymetainfojob.h \
downloadarchivesjob.h \
init.h \
updater.h \
@@ -86,7 +85,6 @@ HEADERS += packagemanagercore.h \
minimumprogressoperation.h \
performinstallationform.h \
messageboxhandler.h \
- getrepositoriesmetainfojob.h \
licenseoperation.h \
component_p.h \
qtcreator_constants.h \
@@ -104,7 +102,17 @@ HEADERS += packagemanagercore.h \
graph.h \
settingsoperation.h \
testrepository.h \
- packagemanagerpagefactory.h
+ packagemanagerpagefactory.h \
+ abstracttask.h\
+ abstractfiletask.h \
+ copyfiletask.h \
+ downloadfiletask.h \
+ downloadfiletask_p.h \
+ unziptask.h \
+ observer.h \
+ runextensions.h \
+ metadatajob.h \
+ metadatajob_p.h
SOURCES += packagemanagercore.cpp \
packagemanagercore_p.cpp \
@@ -136,7 +144,6 @@ HEADERS += packagemanagercore.h \
environmentvariablesoperation.cpp \
installiconsoperation.cpp \
selfrestartoperation.cpp \
- getrepositorymetainfojob.cpp \
downloadarchivesjob.cpp \
init.cpp \
updater.cpp \
@@ -152,7 +159,6 @@ HEADERS += packagemanagercore.h \
minimumprogressoperation.cpp \
performinstallationform.cpp \
messageboxhandler.cpp \
- getrepositoriesmetainfojob.cpp \
licenseoperation.cpp \
component_p.cpp \
qprocesswrapper.cpp \
@@ -169,7 +175,13 @@ HEADERS += packagemanagercore.h \
globals.cpp \
settingsoperation.cpp \
testrepository.cpp \
- packagemanagerpagefactory.cpp
+ packagemanagerpagefactory.cpp \
+ abstractfiletask.cpp \
+ copyfiletask.cpp \
+ downloadfiletask.cpp \
+ unziptask.cpp \
+ observer.cpp \
+ metadatajob.cpp
RESOURCES += resources/patch_file_lists.qrc \
resources/installer.qrc
diff --git a/src/libs/installer/link.cpp b/src/libs/installer/link.cpp
index d7588d077..aebf665d1 100644
--- a/src/libs/installer/link.cpp
+++ b/src/libs/installer/link.cpp
@@ -45,7 +45,7 @@
#include <QDir>
#include <QDebug>
-#ifdef Q_OS_LINUX
+#ifdef Q_OS_UNIX
#include <unistd.h>
#endif
diff --git a/src/libs/installer/metadatajob.cpp b/src/libs/installer/metadatajob.cpp
new file mode 100644
index 000000000..d326b70bd
--- /dev/null
+++ b/src/libs/installer/metadatajob.cpp
@@ -0,0 +1,380 @@
+/**************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+#include "metadatajob.h"
+#include "errors.h"
+#include "messageboxhandler.h"
+#include "metadatajob_p.h"
+#include "packagemanagercore.h"
+#include "productkeycheck.h"
+#include "qinstallerglobal.h"
+#include "settings.h"
+
+namespace QInstaller {
+
+MetadataJob::MetadataJob(QObject *parent)
+ : KDJob(parent)
+ , m_core(0)
+{
+ setCapabilities(Cancelable);
+ connect(&m_xmlTask, SIGNAL(finished()), this, SLOT(xmlTaskFinished()));
+ connect(&m_metadataTask, SIGNAL(finished()), this, SLOT(metadataTaskFinished()));
+ connect(&m_metadataTask, SIGNAL(progressValueChanged(int)), this, SLOT(progressChanged(int)));
+}
+
+MetadataJob::~MetadataJob()
+{
+ reset();
+}
+
+Repository MetadataJob::repositoryForDirectory(const QString &directory) const
+{
+ return m_metadata.value(directory).repository;
+}
+
+
+// -- private slots
+
+void MetadataJob::doStart()
+{
+ reset();
+ if (!m_core) {
+ emitFinishedWithError(KDJob::Canceled, tr("Missing package manager core engine."));
+ return; // We can't do anything here without core, so avoid tons of !m_core checks.
+ }
+
+ emit infoMessage(this, tr("Preparing meta information download..."));
+ const bool onlineInstaller = m_core->isInstaller() && !m_core->isOfflineOnly();
+ if (onlineInstaller || (m_core->isUpdater() || m_core->isPackageManager())) {
+ QList<FileTaskItem> items;
+ const ProductKeyCheck *const productKeyCheck = ProductKeyCheck::instance();
+ foreach (const Repository &repo, m_core->settings().repositories()) {
+ if (repo.isEnabled() && productKeyCheck->isValidRepository(repo)) {
+ QAuthenticator authenticator;
+ authenticator.setUser(repo.username());
+ authenticator.setPassword(repo.password());
+
+ // append a random string to avoid proxy caches
+ FileTaskItem item(repo.url().toString() + QString::fromLatin1("/Updates.xml?")
+ .append(QString::number(qrand() * qrand())));
+ item.insert(TaskRole::UserRole, QVariant::fromValue(repo));
+ item.insert(TaskRole::Authenticator, QVariant::fromValue(authenticator));
+ items.append(item);
+ }
+ }
+ DownloadFileTask *const xmlTask = new DownloadFileTask(items);
+ m_xmlTask.setFuture(QtConcurrent::run(&DownloadFileTask::doTask, xmlTask));
+ } else {
+ emitFinished();
+ }
+}
+
+void MetadataJob::doCancel()
+{
+ reset();
+ emitFinishedWithError(KDJob::Canceled, tr("Meta data download canceled."));
+}
+
+void MetadataJob::xmlTaskFinished()
+{
+ Status status = XmlDownloadFailure;
+ try {
+ m_xmlTask.waitForFinished();
+ status = parseUpdatesXml(m_xmlTask.future().results());
+ } catch (const FileTaskException &e) {
+ reset();
+ emitFinishedWithError(QInstaller::DownloadError, e.message());
+ } catch (const QUnhandledException &e) {
+ reset();
+ emitFinishedWithError(QInstaller::DownloadError, QLatin1String(e.what()));
+ } catch (...) {
+ reset();
+ emitFinishedWithError(QInstaller::DownloadError, tr("Unknown exception during download."));
+ }
+
+ if (error() != KDJob::NoError)
+ return;
+
+ if (status == XmlDownloadSuccess) {
+ setProcessedAmount(0);
+ DownloadFileTask *const metadataTask = new DownloadFileTask(m_packages);
+ m_metadataTask.setFuture(QtConcurrent::run(&DownloadFileTask::doTask, metadataTask));
+ emit infoMessage(this, tr("Retrieving meta information from remote repository..."));
+ } else if (status == XmlDownloadRetry) {
+ QMetaObject::invokeMethod(this, "doStart", Qt::QueuedConnection);
+ } else {
+ reset();
+ emitFinishedWithError(QInstaller::DownloadError, tr("Failure to fetch repositories."));
+ }
+}
+
+void MetadataJob::unzipTaskFinished()
+{
+ QFutureWatcher<void> *watcher = static_cast<QFutureWatcher<void> *>(sender());
+ try {
+ watcher->waitForFinished(); // trigger possible exceptions
+ } catch (const UnzipArchiveException &e) {
+ reset();
+ emitFinishedWithError(QInstaller::ExtractionError, e.message());
+ } catch (const QUnhandledException &e) {
+ reset();
+ emitFinishedWithError(QInstaller::DownloadError, QLatin1String(e.what()));
+ } catch (...) {
+ reset();
+ emitFinishedWithError(QInstaller::DownloadError, tr("Unknown exception during extracting."));
+ }
+ delete m_unzipTasks.value(watcher);
+ m_unzipTasks.remove(watcher);
+ delete watcher;
+
+ if (error() != KDJob::NoError)
+ return;
+ if (m_unzipTasks.isEmpty()) {
+ setProcessedAmount(100);
+ emitFinished();
+ }
+}
+
+void MetadataJob::progressChanged(int progress)
+{
+ setProcessedAmount(progress);
+}
+
+void MetadataJob::metadataTaskFinished()
+{
+ try {
+ m_metadataTask.waitForFinished();
+ QFuture<FileTaskResult> future = m_metadataTask.future();
+ if (future.resultCount() > 0) {
+ emit infoMessage(this, tr("Extracting meta information..."));
+ foreach (const FileTaskResult &result, future.results()) {
+ const FileTaskItem item = result.value(TaskRole::TaskItem).value<FileTaskItem>();
+ UnzipArchiveTask *task = new UnzipArchiveTask(result.target(),
+ item.value(TaskRole::UserRole).toString());
+
+ QFutureWatcher<void> *watcher = new QFutureWatcher<void>();
+ m_unzipTasks.insert(watcher, qobject_cast<QObject*> (task));
+ connect(watcher, SIGNAL(finished()), this, SLOT(unzipTaskFinished()));
+ watcher->setFuture(QtConcurrent::run(&UnzipArchiveTask::doTask, task));
+ }
+ } else {
+ emitFinished();
+ }
+ } catch (const FileTaskException &e) {
+ reset();
+ emitFinishedWithError(QInstaller::DownloadError, e.message());
+ } catch (const QUnhandledException &e) {
+ reset();
+ emitFinishedWithError(QInstaller::DownloadError, QLatin1String(e.what()));
+ } catch (...) {
+ reset();
+ emitFinishedWithError(QInstaller::DownloadError, tr("Unknown exception during download."));
+ }
+}
+
+
+// -- private
+
+void MetadataJob::reset()
+{
+ m_packages.clear();
+ m_metadata.clear();
+
+ setError(KDJob::NoError);
+ setErrorString(QString());
+ setCapabilities(Cancelable);
+
+ try {
+ m_xmlTask.cancel();
+ m_metadataTask.cancel();
+ foreach (QFutureWatcher<void> *const watcher, m_unzipTasks.keys())
+ watcher->cancel();
+ foreach (QObject *const object, m_unzipTasks)
+ object->deleteLater();
+ } catch (...) {}
+ m_tempDirDeleter.releaseAndDeleteAll();
+}
+
+MetadataJob::Status MetadataJob::parseUpdatesXml(const QList<FileTaskResult> &results)
+{
+ foreach (const FileTaskResult &result, results) {
+ if (error() != KDJob::NoError)
+ return XmlDownloadFailure;
+
+ Metadata metadata;
+ try {
+ metadata.directory = createTemporaryDirectory(QLatin1String("remoterepo-"));
+ m_tempDirDeleter.add(metadata.directory);
+ } catch (const QInstaller::Error &error) {
+ qDebug() << error.message();
+ return XmlDownloadFailure;
+ }
+
+ QFile file(result.target());
+ if (!file.rename(metadata.directory + QLatin1String("/Updates.xml"))) {
+ qDebug() << "Could not rename target to Updates.xml. Error:" << file.errorString();
+ return XmlDownloadFailure;
+ }
+
+ if (!file.open(QIODevice::ReadOnly)) {
+ qDebug() << "Could not open Updates.xml for reading. Error:" << file.errorString();
+ return XmlDownloadFailure;
+ }
+
+ QString error;
+ QDomDocument doc;
+ if (!doc.setContent(&file, &error)) {
+ qDebug() << QString::fromLatin1("Could not fetch a valid version of Updates.xml from "
+ "repository: %1. Error: %2").arg(metadata.repository.displayname(), error);
+ return XmlDownloadFailure;
+ }
+ file.close();
+
+ const FileTaskItem item = result.value(TaskRole::TaskItem).value<FileTaskItem>();
+ metadata.repository = item.value(TaskRole::UserRole).value<Repository>();
+ const bool online = !(metadata.repository.url().scheme()).isEmpty();
+
+ const QDomElement root = doc.documentElement();
+ QDomNodeList children = root.childNodes();
+ for (int i = 0; i < children.count(); ++i) {
+ const QDomElement el = children.at(i).toElement();
+ if (!el.isNull() && el.tagName() == QLatin1String("PackageUpdate")) {
+ const QDomNodeList c2 = el.childNodes();
+ QString packageName, packageVersion, packageHash;
+ for (int j = 0; j < c2.count(); ++j) {
+ if (c2.at(j).toElement().tagName() == scName)
+ packageName = c2.at(j).toElement().text();
+ else if (c2.at(j).toElement().tagName() == scRemoteVersion)
+ packageVersion = c2.at(j).toElement().text();
+ else if (c2.at(j).toElement().tagName() == QLatin1String("SHA1"))
+ packageHash = c2.at(j).toElement().text();
+ }
+ const QString repoUrl = metadata.repository.url().toString();
+ FileTaskItem item(QString::fromLatin1("%1/%2/%3meta.7z").arg(repoUrl,
+ packageName, (online ? packageVersion : QString())));
+ item.insert(TaskRole::UserRole, metadata.directory);
+ item.insert(TaskRole::Checksum, packageHash.toLatin1());
+ m_packages.append(item);
+ }
+ }
+ m_metadata.insert(metadata.directory, metadata);
+
+ // search for additional repositories that we might need to check
+ const QDomNode repositoryUpdate = root.firstChildElement(QLatin1String("RepositoryUpdate"));
+ if (repositoryUpdate.isNull())
+ continue;
+
+ QHash<QString, QPair<Repository, Repository> > repositoryUpdates;
+ children = repositoryUpdate.toElement().childNodes();
+ for (int i = 0; i < children.count(); ++i) {
+ const QDomElement el = children.at(i).toElement();
+ if (!el.isNull() && el.tagName() == QLatin1String("Repository")) {
+ const QString action = el.attribute(QLatin1String("action"));
+ if (action == QLatin1String("add")) {
+ // add a new repository to the defaults list
+ Repository repository(el.attribute(QLatin1String("url")), true);
+ repository.setUsername(el.attribute(QLatin1String("username")));
+ repository.setPassword(el.attribute(QLatin1String("password")));
+ repository.setDisplayName(el.attribute(QLatin1String("displayname")));
+ if (ProductKeyCheck::instance()->isValidRepository(repository)) {
+ repositoryUpdates.insertMulti(action, qMakePair(repository, Repository()));
+ qDebug() << "Repository to add:" << repository.displayname();
+ }
+ } else if (action == QLatin1String("remove")) {
+ // remove possible default repositories using the given server url
+ Repository repository(el.attribute(QLatin1String("url")), true);
+ repositoryUpdates.insertMulti(action, qMakePair(repository, Repository()));
+
+ qDebug() << "Repository to remove:" << repository.displayname();
+ } else if (action == QLatin1String("replace")) {
+ // replace possible default repositories using the given server url
+ Repository oldRepository(el.attribute(QLatin1String("oldUrl")), true);
+ Repository newRepository(el.attribute(QLatin1String("newUrl")), true);
+ newRepository.setUsername(el.attribute(QLatin1String("username")));
+ newRepository.setPassword(el.attribute(QLatin1String("password")));
+ newRepository.setDisplayName(el.attribute(QLatin1String("displayname")));
+
+ if (ProductKeyCheck::instance()->isValidRepository(newRepository)) {
+ // store the new repository and the one old it replaces
+ repositoryUpdates.insertMulti(action, qMakePair(newRepository, oldRepository));
+ qDebug() << "Replace repository:" << oldRepository.displayname() << "with:"
+ << newRepository.displayname();
+ }
+ } else {
+ qDebug() << "Invalid additional repositories action set in Updates.xml fetched "
+ "from:" << metadata.repository.displayname() << "Line:" << el.lineNumber();
+ }
+ }
+ }
+
+ if (!repositoryUpdates.isEmpty()) {
+ Settings &s = m_core->settings();
+ const QSet<Repository> temporaries = s.temporaryRepositories();
+ // in case the temp repository introduced something new, we only want that temporary
+ if (temporaries.contains(metadata.repository)) {
+ QSet<Repository> tmpRepositories;
+ typedef QPair<Repository, Repository> RepositoryPair;
+
+ QList<RepositoryPair> values = repositoryUpdates.values(QLatin1String("add"));
+ foreach (const RepositoryPair &value, values)
+ tmpRepositories.insert(value.first);
+
+ values = repositoryUpdates.values(QLatin1String("replace"));
+ foreach (const RepositoryPair &value, values)
+ tmpRepositories.insert(value.first);
+
+ tmpRepositories = tmpRepositories.subtract(temporaries);
+ if (tmpRepositories.count() > 0) {
+ s.addTemporaryRepositories(tmpRepositories, true);
+ QFile::remove(result.target());
+ return XmlDownloadRetry;
+ }
+ } else if (s.updateDefaultRepositories(repositoryUpdates) == Settings::UpdatesApplied) {
+ if (m_core->isUpdater() || m_core->isPackageManager())
+ m_core->writeMaintenanceConfigFiles();
+ QFile::remove(result.target());
+ return XmlDownloadRetry;
+ }
+ }
+ }
+ return XmlDownloadSuccess;
+}
+
+} // namespace QInstaller
diff --git a/src/libs/installer/getrepositoriesmetainfojob.h b/src/libs/installer/metadatajob.h
index 2cc53b82a..a10eb083b 100644
--- a/src/libs/installer/getrepositoriesmetainfojob.h
+++ b/src/libs/installer/metadatajob.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2012-2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Installer Framework.
@@ -38,68 +38,70 @@
** $QT_END_LICENSE$
**
**************************************************************************/
-#ifndef GETREPOSITORIESMETAINFOJOB_H
-#define GETREPOSITORIESMETAINFOJOB_H
-#include "fileutils.h"
-#include "installer_global.h"
-#include "repository.h"
+#ifndef METADATAJOB_H
+#define METADATAJOB_H
+#include "downloadfiletask.h"
+#include "fileutils.h"
#include "kdjob.h"
+#include "repository.h"
-#include <QtCore/QList>
-#include <QtCore/QPointer>
-#include <QtCore/QString>
-#include <QtCore/QStringList>
-
-namespace KDUpdater {
- class FileDownloader;
-}
+#include <QFutureWatcher>
namespace QInstaller {
-class GetRepositoryMetaInfoJob;
class PackageManagerCore;
-class INSTALLER_EXPORT GetRepositoriesMetaInfoJob : public KDJob
+struct Metadata
+{
+ QString directory;
+ Repository repository;
+};
+
+class INSTALLER_EXPORT MetadataJob : public KDJob
{
Q_OBJECT
+ Q_DISABLE_COPY(MetadataJob)
+
+ enum Status {
+ XmlDownloadRetry,
+ XmlDownloadFailure,
+ XmlDownloadSuccess
+ };
public:
- explicit GetRepositoriesMetaInfoJob(PackageManagerCore *core);
+ explicit MetadataJob(QObject *parent = 0);
+ ~MetadataJob();
- QStringList temporaryDirectories() const;
- QStringList releaseTemporaryDirectories() const;
- Repository repositoryForTemporaryDirectory(const QString &tmpDir) const;
+ QList<Metadata> metadata() const { return m_metadata.values(); }
+ Repository repositoryForDirectory(const QString &directory) const;
+ void setPackageManagerCore(PackageManagerCore *core) { m_core = core; }
- int numberOfRetrievedRepositories() const;
+private slots:
+ void doStart();
+ void doCancel();
- int silentRetries() const;
- void setSilentRetries(int retries);
+ void xmlTaskFinished();
+ void unzipTaskFinished();
+ void metadataTaskFinished();
+ void progressChanged(int progress);
+private:
void reset();
- bool isCanceled() const;
-
-private Q_SLOTS:
- /* reimp */ void doStart();
- /* reimp */ void doCancel();
-
- void fetchNextRepo();
- void jobFinished(KDJob*);
+ Status parseUpdatesXml(const QList<FileTaskResult> &results);
private:
- bool m_canceled;
- int m_silentRetries;
- bool m_haveIgnoredError;
PackageManagerCore *m_core;
- QString m_errorString;
- QList<Repository> m_repositories;
- mutable TempDirDeleter m_tempDirDeleter;
- QPointer<GetRepositoryMetaInfoJob> m_job;
- QHash<QString, Repository> m_repositoryByTemporaryDirectory;
+ QList<FileTaskItem> m_packages;
+ TempDirDeleter m_tempDirDeleter;
+ QHash<QString, Metadata> m_metadata;
+ QFutureWatcher<FileTaskResult> m_xmlTask;
+ QFutureWatcher<FileTaskResult> m_metadataTask;
+ QHash<QFutureWatcher<void> *, QObject*> m_unzipTasks;
};
} // namespace QInstaller
-#endif // GETREPOSITORIESMETAINFOJOB_H
+#endif // METADATAJOB_H
diff --git a/src/libs/installer/metadatajob_p.h b/src/libs/installer/metadatajob_p.h
new file mode 100644
index 000000000..3b1835a3c
--- /dev/null
+++ b/src/libs/installer/metadatajob_p.h
@@ -0,0 +1,120 @@
+/**************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+
+#ifndef METADATAJOB_P_H
+#define METADATAJOB_P_H
+
+#include "lib7z_facade.h"
+#include "metadatajob.h"
+
+namespace QInstaller{
+
+class UnzipArchiveException : public QException
+{
+public:
+ UnzipArchiveException() {}
+ ~UnzipArchiveException() throw() {}
+ explicit UnzipArchiveException(const QString &message)
+ : m_message(message)
+ {}
+
+ void raise() const { throw *this; }
+ QString message() const { return m_message; }
+ UnzipArchiveException *clone() const { return new UnzipArchiveException(*this); }
+
+private:
+ QString m_message;
+};
+
+class UnzipArchiveTask : public AbstractTask<void>
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(UnzipArchiveTask)
+
+public:
+ UnzipArchiveTask(const QString &arcive, const QString &target)
+ : m_archive(arcive), m_targetDir(target)
+ {}
+ ~UnzipArchiveTask()
+ {
+ QFile file(m_archive);
+ if (!file.remove()) {
+ qWarning("Could not delete file %s: %s", qPrintable(m_archive), qPrintable(file
+ .errorString()));
+ }
+ }
+ void doTask(QFutureInterface<void> &fi)
+ {
+ fi.reportStarted();
+ fi.setExpectedResultCount(1);
+
+ if (fi.isCanceled()) {
+ fi.reportFinished();
+ return; // ignore already canceled
+ }
+
+ QFile archive(m_archive);
+ if (archive.open(QIODevice::ReadOnly)) {
+ try {
+ Lib7z::extractArchive(&archive, m_targetDir);
+ } catch (const Lib7z::SevenZipException& e) {
+ fi.reportException(UnzipArchiveException(MetadataJob::tr("Error while extracting "
+ "'%1': %2").arg(m_archive, e.message())));
+ } catch (...) {
+ fi.reportException(UnzipArchiveException(MetadataJob::tr("Unknown exception "
+ "caught while extracting %1.").arg(m_archive)));
+ }
+ } else {
+ fi.reportException(UnzipArchiveException(MetadataJob::tr("Could not open %1 for "
+ "reading. Error: %2").arg(m_archive, archive.errorString())));
+ }
+
+ fi.reportFinished();
+ }
+
+private:
+ QString m_archive;
+ QString m_targetDir;
+};
+
+} // namespace QInstaller
+
+#endif // METADATAJOB_P_H
diff --git a/src/libs/installer/observer.cpp b/src/libs/installer/observer.cpp
new file mode 100644
index 000000000..617cd744d
--- /dev/null
+++ b/src/libs/installer/observer.cpp
@@ -0,0 +1,191 @@
+/**************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+#include "observer.h"
+
+#include <fileutils.h>
+
+namespace QInstaller {
+
+FileTaskObserver::FileTaskObserver(QCryptographicHash::Algorithm algorithm)
+ : m_hash(algorithm)
+{
+ init();
+}
+
+FileTaskObserver::~FileTaskObserver()
+{
+ if (m_timerId >= 0)
+ killTimer(m_timerId);
+}
+
+int FileTaskObserver::progressValue() const
+{
+ if (m_bytesToTransfer <= 0 || m_bytesTransfered > m_bytesToTransfer)
+ return 0;
+ return 100 * m_bytesTransfered / m_bytesToTransfer;
+}
+
+QString FileTaskObserver::progressText() const
+{
+ QString progressText;
+ if (m_bytesToTransfer > 0) {
+ QString bytesReceived = QInstaller::humanReadableSize(m_bytesTransfered);
+ const QString bytesToReceive = QInstaller::humanReadableSize(m_bytesToTransfer);
+
+ // remove the unit from the bytesReceived value if bytesToReceive has the same
+ const QString tmp = bytesToReceive.mid(bytesToReceive.indexOf(QLatin1Char(' ')));
+ if (bytesReceived.endsWith(tmp))
+ bytesReceived.chop(tmp.length());
+
+ progressText = bytesReceived + tr(" of ") + bytesToReceive;
+ } else {
+ if (m_bytesTransfered > 0)
+ progressText = QInstaller::humanReadableSize(m_bytesTransfered) + tr(" received.");
+ }
+
+ progressText += QLatin1String(" (") + QInstaller::humanReadableSize(m_bytesPerSecond) + tr("/sec")
+ + QLatin1Char(')');
+ if (m_bytesToTransfer > 0 && m_bytesPerSecond > 0) {
+ const qint64 time = (m_bytesToTransfer - m_bytesTransfered) / m_bytesPerSecond;
+
+ int s = time % 60;
+ const int d = time / 86400;
+ const int h = (time / 3600) - (d * 24);
+ const int m = (time / 60) - (d * 1440) - (h * 60);
+
+ QString days;
+ if (d > 0)
+ days = QString::number(d) + (d < 2 ? tr(" day") : tr(" days")) + QLatin1String(", ");
+
+ QString hours;
+ if (h > 0)
+ hours = QString::number(h) + (h < 2 ? tr(" hour") : tr(" hours")) + QLatin1String(", ");
+
+ QString minutes;
+ if (m > 0)
+ minutes = QString::number(m) + (m < 2 ? tr(" minute") : tr(" minutes"));
+
+ QString seconds;
+ if (s >= 0 && minutes.isEmpty()) {
+ s = (s <= 0 ? 1 : s);
+ seconds = QString::number(s) + (s < 2 ? tr(" second") : tr(" seconds"));
+ }
+ progressText += tr(" - ") + days + hours + minutes + seconds + tr(" remaining.");
+ } else {
+ progressText += tr(" - unknown time remaining.");
+ }
+
+ return progressText;
+}
+
+QByteArray FileTaskObserver::checkSum() const
+{
+ return m_hash.result();
+}
+
+void FileTaskObserver::addCheckSumData(const char *data, int length)
+{
+ m_hash.addData(data, length);
+}
+
+void FileTaskObserver::addSample(qint64 sample)
+{
+ m_currentSpeedBin += sample;
+}
+
+void FileTaskObserver::setBytesTransfered(qint64 bytesReceived)
+{
+ m_bytesTransfered = bytesReceived;
+}
+
+void FileTaskObserver::addBytesTransfered(qint64 bytesReceived)
+{
+ m_bytesTransfered += bytesReceived;
+}
+
+void FileTaskObserver::setBytesToTransfer(qint64 bytesToReceive)
+{
+ m_bytesToTransfer = bytesToReceive;
+}
+
+
+// -- private
+
+void FileTaskObserver::init()
+{
+ m_hash.reset();
+ m_sampleIndex = 0;
+ m_bytesTransfered = 0;
+ m_bytesToTransfer = 0;
+ m_bytesPerSecond = 0;
+ m_currentSpeedBin = 0;
+
+ m_timerId = -1;
+ m_timerInterval = 100;
+ memset(m_samples, 0, sizeof(m_samples));
+ m_timerId = startTimer(m_timerInterval);
+}
+
+void FileTaskObserver::timerEvent(QTimerEvent *event)
+{
+ Q_UNUSED(event)
+ unsigned int windowSize = sizeof(m_samples) / sizeof(qint64);
+
+ // add speed of last time bin to the window
+ m_samples[m_sampleIndex % windowSize] = m_currentSpeedBin;
+ m_currentSpeedBin = 0; // reset bin for next time interval
+
+ // advance the sample index
+ m_sampleIndex++;
+ m_bytesPerSecond = 0;
+
+ // dynamic window size until the window is completely filled
+ if (m_sampleIndex < windowSize)
+ windowSize = m_sampleIndex;
+
+ for (unsigned int i = 0; i < windowSize; ++i)
+ m_bytesPerSecond += m_samples[i];
+
+ m_bytesPerSecond /= windowSize; // computer average
+ m_bytesPerSecond *= 1000.0 / m_timerInterval; // rescale to bytes/second
+}
+
+} // namespace QInstaller
diff --git a/src/libs/installer/observer.h b/src/libs/installer/observer.h
new file mode 100644
index 000000000..539d6b2da
--- /dev/null
+++ b/src/libs/installer/observer.h
@@ -0,0 +1,105 @@
+/**************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+
+#ifndef OBSERVER_H
+#define OBSERVER_H
+
+#include <QCryptographicHash>
+#include <QObject>
+
+namespace QInstaller {
+
+class Observer : public QObject
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(Observer)
+
+public:
+ Observer() {}
+ virtual ~Observer() {}
+
+ virtual int progressValue() const = 0;
+ virtual QString progressText() const = 0;
+};
+
+class FileTaskObserver : public Observer
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(FileTaskObserver)
+
+public:
+ FileTaskObserver(QCryptographicHash::Algorithm algorithm);
+ ~FileTaskObserver();
+
+ int progressValue() const;
+ QString progressText() const;
+
+ QByteArray checkSum() const;
+ void addCheckSumData(const char *data, int length);
+
+ void addSample(qint64 sample);
+ void timerEvent(QTimerEvent *event);
+
+ void setBytesTransfered(qint64 bytesTransfered);
+ void addBytesTransfered(qint64 bytesTransfered);
+ void setBytesToTransfer(qint64 bytesToTransfer);
+
+private:
+ void init();
+
+private:
+ int m_timerId;
+ int m_timerInterval;
+
+ qint64 m_bytesTransfered;
+ qint64 m_bytesToTransfer;
+
+ qint64 m_samples[50];
+ quint32 m_sampleIndex;
+ qint64 m_bytesPerSecond;
+ qint64 m_currentSpeedBin;
+
+ QCryptographicHash m_hash;
+};
+
+} // namespace QInstaller
+
+#endif // OBSERVER_H
diff --git a/src/libs/installer/packagemanagercore.cpp b/src/libs/installer/packagemanagercore.cpp
index a4883b651..b90435993 100644
--- a/src/libs/installer/packagemanagercore.cpp
+++ b/src/libs/installer/packagemanagercore.cpp
@@ -49,7 +49,6 @@
#include "errors.h"
#include "fsengineclient.h"
#include "globals.h"
-#include "getrepositoriesmetainfojob.h"
#include "messageboxhandler.h"
#include "packagemanagerproxyfactory.h"
#include "progresscoordinator.h"
@@ -185,10 +184,16 @@
*/
/*!
+ \qmlsignal QInstaller::metaJobProgress(int progress)
+
+ Triggered with progress updates of the while communicating with a remote repository. Progress
+ ranges from 0 to 100.
+*/
+
+/*!
\qmlsignal QInstaller::metaJobInfoMessage(string message)
Triggered with informative updates of the communication with a remote repository.
- This is only useful for debugging purposes.
*/
/*!
@@ -459,8 +464,7 @@ void PackageManagerCore::setCompleteUninstallation(bool complete)
*/
void PackageManagerCore::cancelMetaInfoJob()
{
- if (d->m_repoMetaInfoJob)
- d->m_repoMetaInfoJob->cancel();
+ d->m_metadataJob.cancel();
}
/*!
@@ -1534,7 +1538,6 @@ bool PackageManagerCore::localInstallerBinaryUsed()
QList<QVariant> PackageManagerCore::execute(const QString &program, const QStringList &arguments,
const QString &stdIn) const
{
- QEventLoop loop;
QProcessWrapper process;
QString adjustedProgram = replaceVariables(program);
@@ -1543,7 +1546,6 @@ QList<QVariant> PackageManagerCore::execute(const QString &program, const QStrin
adjustedArguments.append(replaceVariables(argument));
QString adjustedStdIn = replaceVariables(stdIn);
- connect(&process, SIGNAL(finished(int, QProcess::ExitStatus)), &loop, SLOT(quit()));
process.start(adjustedProgram, adjustedArguments,
adjustedStdIn.isNull() ? QIODevice::ReadOnly : QIODevice::ReadWrite);
@@ -1555,8 +1557,7 @@ QList<QVariant> PackageManagerCore::execute(const QString &program, const QStrin
process.closeWriteChannel();
}
- if (process.state() != QProcessWrapper::NotRunning)
- loop.exec();
+ process.waitForFinished(-1);
return QList<QVariant>() << QString::fromLatin1(process.readAllStandardOutput()) << process.exitCode();
}
@@ -2099,8 +2100,9 @@ bool PackageManagerCore::updateComponentData(struct Data &data, Component *compo
lastLocalPath = localPath;
}
- if (d->m_repoMetaInfoJob) {
- const Repository &repo = d->m_repoMetaInfoJob->repositoryForTemporaryDirectory(localPath);
+
+ const Repository repo = d->m_metadataJob.repositoryForDirectory(localPath);
+ if (repo.isValid()) {
component->setRepositoryUrl(repo.url());
component->setValue(QLatin1String("username"), repo.username());
component->setValue(QLatin1String("password"), repo.password());
diff --git a/src/libs/installer/packagemanagercore.h b/src/libs/installer/packagemanagercore.h
index 5f262e804..a3f2b7eb0 100644
--- a/src/libs/installer/packagemanagercore.h
+++ b/src/libs/installer/packagemanagercore.h
@@ -279,6 +279,7 @@ Q_SIGNALS:
void currentPageChanged(int page);
void finishButtonClicked();
+ void metaJobProgress(int progress);
void metaJobInfoMessage(const QString &message);
void startAllComponentsReset();
diff --git a/src/libs/installer/packagemanagercore_p.cpp b/src/libs/installer/packagemanagercore_p.cpp
index c54a0e242..c73a7fc82 100644
--- a/src/libs/installer/packagemanagercore_p.cpp
+++ b/src/libs/installer/packagemanagercore_p.cpp
@@ -207,7 +207,6 @@ PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core)
, m_updaterApplication(new DummyConfigurationInterface)
, m_FSEngineClientHandler(0)
, m_core(core)
- , m_repoMetaInfoJob(0)
, m_updates(false)
, m_repoFetched(false)
, m_updateSourcesAdded(false)
@@ -235,7 +234,6 @@ PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core, q
, m_performedOperationsOld(performedOperations)
, m_dependsOnLocalInstallerBinary(false)
, m_core(core)
- , m_repoMetaInfoJob(0)
, m_updates(false)
, m_repoFetched(false)
, m_updateSourcesAdded(false)
@@ -654,12 +652,13 @@ void PackageManagerCorePrivate::initialize(const QHash<QString, QString> &params
m_updaterApplication.updateSourcesInfo()->setModified(false);
}
- if (!m_repoMetaInfoJob) {
- m_repoMetaInfoJob = new GetRepositoriesMetaInfoJob(m_core);
- m_repoMetaInfoJob->setAutoDelete(false);
- connect(m_repoMetaInfoJob, SIGNAL(infoMessage(KDJob*, QString)), this, SLOT(infoMessage(KDJob*,
- QString)));
- }
+ m_metadataJob.disconnect();
+ m_metadataJob.setAutoDelete(false);
+ m_metadataJob.setPackageManagerCore(m_core);
+ connect(&m_metadataJob, SIGNAL(infoMessage(KDJob*, QString)), this,
+ SLOT(infoMessage(KDJob*, QString)));
+ connect(&m_metadataJob, SIGNAL(progress(KDJob *, quint64, quint64)), this,
+ SLOT(infoProgress(KDJob *, quint64, quint64)));
KDUpdater::FileDownloaderFactory::instance().setProxyFactory(m_core->proxyFactory());
}
@@ -945,7 +944,7 @@ void PackageManagerCorePrivate::stopProcessesForUpdates(const QList<Component*>
foreach (const Component *component, components)
processList << m_core->replaceVariables(component->stopProcessForUpdateRequests());
- qSort(processList);
+ std::sort(processList.begin(), processList.end());
processList.erase(std::unique(processList.begin(), processList.end()), processList.end());
if (processList.isEmpty())
return;
@@ -2176,21 +2175,21 @@ bool PackageManagerCorePrivate::fetchMetaInformationFromRepositories()
m_repoFetched = false;
m_updateSourcesAdded = false;
- m_repoMetaInfoJob->reset();
try {
- m_repoMetaInfoJob->start();
- m_repoMetaInfoJob->waitForFinished();
+ m_metadataJob.start();
+ m_metadataJob.waitForFinished();
} catch (Error &error) {
- setStatus(PackageManagerCore::Failure, tr("Could not retrieve meta information: %1").arg(error.message()));
+ setStatus(PackageManagerCore::Failure, tr("Could not retrieve meta information: %1")
+ .arg(error.message()));
return m_repoFetched;
}
- if (m_repoMetaInfoJob->isCanceled() || m_repoMetaInfoJob->error() != KDJob::NoError) {
- switch (m_repoMetaInfoJob->error()) {
+ if (m_metadataJob.error() != KDJob::NoError) {
+ switch (m_metadataJob.error()) {
case QInstaller::UserIgnoreError:
break; // we can simply ignore this error, the user knows about it
default:
- setStatus(PackageManagerCore::Failure, m_repoMetaInfoJob->errorString());
+ setStatus(PackageManagerCore::Failure, m_metadataJob.errorString());
return m_repoFetched;
}
}
@@ -2204,7 +2203,8 @@ bool PackageManagerCorePrivate::addUpdateResourcesFromRepositories(bool parseChe
if (m_updateSourcesAdded)
return m_updateSourcesAdded;
- if (m_repoMetaInfoJob->temporaryDirectories().isEmpty()) {
+ const QList<Metadata> metadata = m_metadataJob.metadata();
+ if (metadata.isEmpty()) {
m_updateSourcesAdded = true;
return m_updateSourcesAdded;
}
@@ -2213,7 +2213,8 @@ bool PackageManagerCorePrivate::addUpdateResourcesFromRepositories(bool parseChe
m_updaterApplication.updateSourcesInfo()->refresh();
if (isInstaller()) {
m_updaterApplication.addUpdateSource(m_data.settings().applicationName(),
- m_data.settings().applicationName(), QString(), QUrl(QLatin1String("resource://metadata/")), 0);
+ m_data.settings().applicationName(), QString(),
+ QUrl(QLatin1String("resource://metadata/")), 0);
m_updaterApplication.updateSourcesInfo()->setModified(false);
}
@@ -2221,16 +2222,15 @@ bool PackageManagerCorePrivate::addUpdateResourcesFromRepositories(bool parseChe
m_updateSourcesAdded = false;
const QString &appName = m_data.settings().applicationName();
- const QStringList tempDirs = m_repoMetaInfoJob->temporaryDirectories();
- foreach (const QString &tmpDir, tempDirs) {
+ foreach (const Metadata &data, metadata) {
if (statusCanceledOrFailed())
return false;
- if (tmpDir.isEmpty())
+ if (data.directory.isEmpty())
continue;
if (parseChecksum) {
- const QString updatesXmlPath = tmpDir + QLatin1String("/Updates.xml");
+ const QString updatesXmlPath = data.directory + QLatin1String("/Updates.xml");
QFile updatesFile(updatesXmlPath);
try {
openForRead(&updatesFile, updatesFile.fileName());
@@ -2255,7 +2255,8 @@ bool PackageManagerCorePrivate::addUpdateResourcesFromRepositories(bool parseChe
if (!checksum.isNull())
m_core->setTestChecksum(checksum.toElement().text().toLower() == scTrue);
}
- m_updaterApplication.addUpdateSource(appName, appName, QString(), QUrl::fromLocalFile(tmpDir), 1);
+ m_updaterApplication.addUpdateSource(appName, appName, QString(),
+ QUrl::fromLocalFile(data.directory), 1);
}
m_updaterApplication.updateSourcesInfo()->setModified(false);
diff --git a/src/libs/installer/packagemanagercore_p.h b/src/libs/installer/packagemanagercore_p.h
index a6b9d4438..1d41d9b21 100644
--- a/src/libs/installer/packagemanagercore_p.h
+++ b/src/libs/installer/packagemanagercore_p.h
@@ -42,7 +42,7 @@
#ifndef PACKAGEMANAGERCORE_P_H
#define PACKAGEMANAGERCORE_P_H
-#include "getrepositoriesmetainfojob.h"
+#include "metadatajob.h"
#include "packagemanagercore.h"
#include "packagemanagercoredata.h"
#include "qinstallerglobal.h"
@@ -95,6 +95,7 @@ class PackageManagerCorePrivate : public QObject
{
Q_OBJECT
friend class PackageManagerCore;
+ Q_DISABLE_COPY(PackageManagerCorePrivate)
public:
enum OperationType {
@@ -234,6 +235,9 @@ private slots:
void infoMessage(KDJob *, const QString &message) {
emit m_core->metaJobInfoMessage(message);
}
+ void infoProgress(KDJob *, quint64 progress, quint64) {
+ emit m_core->metaJobProgress(progress);
+ }
void handleMethodInvocationRequest(const QString &invokableMethodName);
@@ -258,7 +262,7 @@ private:
private:
PackageManagerCore *m_core;
- GetRepositoriesMetaInfoJob *m_repoMetaInfoJob;
+ MetadataJob m_metadataJob;
bool m_updates;
bool m_repoFetched;
diff --git a/src/libs/installer/packagemanagergui.cpp b/src/libs/installer/packagemanagergui.cpp
index a59586e9e..1757f21f5 100644
--- a/src/libs/installer/packagemanagergui.cpp
+++ b/src/libs/installer/packagemanagergui.cpp
@@ -126,8 +126,8 @@ public:
setPixmap(QWizard::WatermarkPixmap, QPixmap());
setLayout(new QVBoxLayout);
- setSubTitle(QLatin1String(" "));
- setTitle(widget->windowTitle());
+ setColoredSubTitle(QLatin1String(" "));
+ setColoredTitle(widget->windowTitle());
m_widget->setProperty("complete", true);
m_widget->setProperty("final", false);
widget->installEventFilter(this);
@@ -150,7 +150,7 @@ protected:
if (obj == m_widget) {
switch(event->type()) {
case QEvent::WindowTitleChange:
- setTitle(m_widget->windowTitle());
+ setColoredTitle(m_widget->windowTitle());
break;
case QEvent::DynamicPropertyChange:
@@ -236,6 +236,10 @@ PackageManagerGui::PackageManagerGui(PackageManagerCore *core, QWidget *parent)
setWizardStyle(QWizard::ModernStyle);
setSizeGripEnabled(true);
#endif
+
+ if (!m_core->settings().wizardStyle().isEmpty())
+ setWizardStyle(getStyle(m_core->settings().wizardStyle()));
+
setOption(QWizard::NoBackButtonOnStartPage);
setOption(QWizard::NoBackButtonOnLastPage);
@@ -285,6 +289,19 @@ PackageManagerGui::~PackageManagerGui()
delete d;
}
+QWizard::WizardStyle PackageManagerGui::getStyle(const QString &name)
+{
+ if (name == QLatin1String("Classic"))
+ return QWizard::ClassicStyle;
+ else if (name == QLatin1String("Modern"))
+ return QWizard::ModernStyle;
+ else if (name == QLatin1String("Mac"))
+ return QWizard::MacStyle;
+ else if (name == QLatin1String("Aero"))
+ return QWizard::AeroStyle;
+ return QWizard::ModernStyle;
+}
+
void PackageManagerGui::setAutomatedPageSwitchEnabled(bool request)
{
d->m_autoSwitchPage = request;
@@ -625,6 +642,12 @@ PackageManagerPage::PackageManagerPage(PackageManagerCore *core)
, m_core(core)
, validatorComponent(0)
{
+ if (!m_core->settings().titleColor().isEmpty())
+ m_titleColor = m_core->settings().titleColor();
+ else {
+ QColor defaultColor = style()->standardPalette().text().color();
+ m_titleColor = defaultColor.name();
+ }
setPixmap(QWizard::WatermarkPixmap, watermarkPixmap());
setPixmap(QWizard::BannerPixmap, bannerPixmap());
setPixmap(QWizard::LogoPixmap, logoPixmap());
@@ -655,6 +678,18 @@ QString PackageManagerPage::productName() const
return m_core->value(QLatin1String("ProductName"));
}
+void PackageManagerPage::setColoredTitle(const QString &title)
+{
+ QString coloredTitle = QString::fromLatin1("<font color=\"%1\">%2</font>").arg(m_titleColor, title);
+ setTitle(coloredTitle);
+}
+
+void PackageManagerPage::setColoredSubTitle(const QString &subTitle)
+{
+ QString coloredTitle = QString::fromLatin1("<font color=\"%1\">%2</font>").arg(m_titleColor, subTitle);
+ setSubTitle(coloredTitle);
+}
+
bool PackageManagerPage::isComplete() const
{
return m_complete;
@@ -758,7 +793,7 @@ IntroductionPage::IntroductionPage(PackageManagerCore *core)
, m_widget(0)
{
setObjectName(QLatin1String("IntroductionPage"));
- setTitle(tr("Setup - %1").arg(productName()));
+ setColoredTitle(tr("Setup - %1").arg(productName()));
m_msgLabel = new QLabel(this);
m_msgLabel->setWordWrap(true);
@@ -821,7 +856,7 @@ LicenseAgreementPage::LicenseAgreementPage(PackageManagerCore *core)
{
setPixmap(QWizard::WatermarkPixmap, QPixmap());
setObjectName(QLatin1String("LicenseAgreementPage"));
- setTitle(tr("License Agreement"));
+ setColoredTitle(tr("License Agreement"));
m_licenseListWidget = new QListWidget(this);
m_licenseListWidget->setObjectName(QLatin1String("LicenseListWidget"));
@@ -941,7 +976,7 @@ void LicenseAgreementPage::updateUi()
rejectButtonText = tr("I do not accept the licenses.");
}
- setSubTitle(subTitleText);
+ setColoredSubTitle(subTitleText);
m_acceptLabel->setText(acceptButtonText);
m_rejectLabel->setText(rejectButtonText);
@@ -1142,7 +1177,7 @@ ComponentSelectionPage::ComponentSelectionPage(PackageManagerCore *core)
{
setPixmap(QWizard::WatermarkPixmap, QPixmap());
setObjectName(QLatin1String("ComponentSelectionPage"));
- setTitle(tr("Select Components"));
+ setColoredTitle(tr("Select Components"));
}
ComponentSelectionPage::~ComponentSelectionPage()
@@ -1164,7 +1199,7 @@ void ComponentSelectionPage::entering()
if (core->isInstaller()) index = 1;
if (core->isUninstaller()) index = 2;
if (core->isPackageManager()) index = 3;
- setSubTitle(tr(strings[index]));
+ setColoredSubTitle(tr(strings[index]));
d->updateTreeView();
setModified(isComplete());
@@ -1234,7 +1269,7 @@ TargetDirectoryPage::TargetDirectoryPage(PackageManagerCore *core)
{
setPixmap(QWizard::WatermarkPixmap, QPixmap());
setObjectName(QLatin1String("TargetDirectoryPage"));
- setTitle(tr("Installation Folder"));
+ setColoredTitle(tr("Installation Folder"));
QVBoxLayout *layout = new QVBoxLayout(this);
@@ -1353,8 +1388,8 @@ StartMenuDirectoryPage::StartMenuDirectoryPage(PackageManagerCore *core)
{
setPixmap(QWizard::WatermarkPixmap, QPixmap());
setObjectName(QLatin1String("StartMenuDirectoryPage"));
- setTitle(tr("Start Menu shortcuts"));
- setSubTitle(tr("Select the Start Menu in which you would like to create the program's shortcuts. You can "
+ setColoredTitle(tr("Start Menu shortcuts"));
+ setColoredSubTitle(tr("Select the Start Menu in which you would like to create the program's shortcuts. You can "
"also enter a name to create a new folder."));
m_lineEdit = new QLineEdit(this);
@@ -1489,7 +1524,7 @@ void ReadyForInstallationPage::entering()
m_taskDetailsButton->setVisible(false);
m_taskDetailsBrowser->setVisible(false);
setButtonText(QWizard::CommitButton, tr("U&ninstall"));
- setTitle(tr("Ready to Uninstall"));
+ setColoredTitle(tr("Ready to Uninstall"));
m_msgLabel->setText(tr("Setup is now ready to begin removing %1 from your computer.<br>"
"<font color=\"red\">The program directory %2 will be deleted completely</font>, "
"including all content in that directory!")
@@ -1499,12 +1534,12 @@ void ReadyForInstallationPage::entering()
return;
} else if (packageManagerCore()->isPackageManager() || packageManagerCore()->isUpdater()) {
setButtonText(QWizard::CommitButton, tr("U&pdate"));
- setTitle(tr("Ready to Update Packages"));
+ setColoredTitle(tr("Ready to Update Packages"));
m_msgLabel->setText(tr("Setup is now ready to begin updating your installation."));
} else {
Q_ASSERT(packageManagerCore()->isInstaller());
setButtonText(QWizard::CommitButton, tr("&Install"));
- setTitle(tr("Ready to Install"));
+ setColoredTitle(tr("Ready to Install"));
m_msgLabel->setText(tr("Setup is now ready to begin installing %1 on your computer.")
.arg(productName()));
}
@@ -1711,17 +1746,17 @@ void PerformInstallationPage::entering()
if (packageManagerCore()->isUninstaller()) {
setButtonText(QWizard::CommitButton, tr("U&ninstall"));
- setTitle(tr("Uninstalling %1").arg(productName()));
+ setColoredTitle(tr("Uninstalling %1").arg(productName()));
QTimer::singleShot(30, packageManagerCore(), SLOT(runUninstaller()));
} else if (packageManagerCore()->isPackageManager() || packageManagerCore()->isUpdater()) {
setButtonText(QWizard::CommitButton, tr("&Update"));
- setTitle(tr("Updating components of %1").arg(productName()));
+ setColoredTitle(tr("Updating components of %1").arg(productName()));
QTimer::singleShot(30, packageManagerCore(), SLOT(runPackageUpdater()));
} else {
setButtonText(QWizard::CommitButton, tr("&Install"));
- setTitle(tr("Installing %1").arg(productName()));
+ setColoredTitle(tr("Installing %1").arg(productName()));
QTimer::singleShot(30, packageManagerCore(), SLOT(runInstaller()));
}
@@ -1739,7 +1774,7 @@ void PerformInstallationPage::leaving()
void PerformInstallationPage::setTitleMessage(const QString &title)
{
- setTitle(title);
+ setColoredTitle(title);
}
// -- private slots
@@ -1788,7 +1823,7 @@ FinishedPage::FinishedPage(PackageManagerCore *core)
, m_commitButton(0)
{
setObjectName(QLatin1String("FinishedPage"));
- setTitle(tr("Completing the %1 Wizard").arg(productName()));
+ setColoredTitle(tr("Completing the %1 Wizard").arg(productName()));
m_msgLabel = new QLabel(this);
m_msgLabel->setWordWrap(true);
@@ -1865,7 +1900,7 @@ void FinishedPage::entering()
}
} else {
// TODO: how to handle this using the config.xml
- setTitle(tr("The %1 Wizard failed.").arg(productName()));
+ setColoredTitle(tr("The %1 Wizard failed.").arg(productName()));
}
m_runItCheckBox->hide();
@@ -1916,7 +1951,7 @@ RestartPage::RestartPage(PackageManagerCore *core)
: PackageManagerPage(core)
{
setObjectName(QLatin1String("RestartPage"));
- setTitle(tr("Completing the %1 Setup Wizard").arg(productName()));
+ setColoredTitle(tr("Completing the %1 Setup Wizard").arg(productName()));
setFinalPage(false);
setCommitPage(false);
diff --git a/src/libs/installer/packagemanagergui.h b/src/libs/installer/packagemanagergui.h
index 304f5f2a1..948fb346a 100644
--- a/src/libs/installer/packagemanagergui.h
+++ b/src/libs/installer/packagemanagergui.h
@@ -94,6 +94,7 @@ public:
Q_INVOKABLE void setSettingsButtonEnabled(bool enable);
void updateButtonLayout();
+ static QWizard::WizardStyle getStyle(const QString &name);
Q_SIGNALS:
void interrupted();
@@ -153,6 +154,9 @@ public:
virtual QPixmap watermarkPixmap() const;
virtual QPixmap bannerPixmap() const;
+ void setColoredTitle(const QString &title);
+ void setColoredSubTitle(const QString &subTitle);
+
virtual bool isComplete() const;
void setComplete(bool complete);
@@ -189,6 +193,7 @@ protected:
private:
bool m_fresh;
bool m_complete;
+ QString m_titleColor;
bool m_needsSettingsButton;
PackageManagerCore *m_core;
diff --git a/src/libs/installer/runextensions.h b/src/libs/installer/runextensions.h
new file mode 100644
index 000000000..e4c7fb2be
--- /dev/null
+++ b/src/libs/installer/runextensions.h
@@ -0,0 +1,435 @@
+/**************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+
+#ifndef QTCONCURRENT_RUNEX_H
+#define QTCONCURRENT_RUNEX_H
+
+#include <qrunnable.h>
+#include <qfutureinterface.h>
+#include <qthreadpool.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtConcurrent {
+
+template <typename T, typename FunctionPointer>
+class StoredInterfaceFunctionCall0 : public QRunnable
+{
+public:
+ StoredInterfaceFunctionCall0(void (fn)(QFutureInterface<T> &))
+ : fn(fn) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ fn(futureInterface);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+
+};
+template <typename T, typename FunctionPointer, typename Class>
+class StoredInterfaceMemberFunctionCall0 : public QRunnable
+{
+public:
+ StoredInterfaceMemberFunctionCall0(void (Class::*fn)(QFutureInterface<T> &), Class *object)
+ : fn(fn), object(object) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ (object->*fn)(futureInterface);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Class *object;
+
+};
+
+template <typename T, typename FunctionPointer, typename Arg1>
+class StoredInterfaceFunctionCall1 : public QRunnable
+{
+public:
+ StoredInterfaceFunctionCall1(void (fn)(QFutureInterface<T> &, Arg1), const Arg1 &arg1)
+ : fn(fn), arg1(arg1) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ fn(futureInterface, arg1);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Arg1 arg1;
+};
+template <typename T, typename FunctionPointer, typename Class, typename Arg1>
+class StoredInterfaceMemberFunctionCall1 : public QRunnable
+{
+public:
+ StoredInterfaceMemberFunctionCall1(void (Class::*fn)(QFutureInterface<T> &, Arg1), Class *object, const Arg1 &arg1)
+ : fn(fn), object(object), arg1(arg1) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ (object->*fn)(futureInterface, arg1);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Class *object;
+ Arg1 arg1;
+};
+
+template <typename T, typename FunctionPointer, typename Arg1, typename Arg2>
+class StoredInterfaceFunctionCall2 : public QRunnable
+{
+public:
+ StoredInterfaceFunctionCall2(void (fn)(QFutureInterface<T> &, Arg1, Arg2), const Arg1 &arg1, const Arg2 &arg2)
+ : fn(fn), arg1(arg1), arg2(arg2) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ fn(futureInterface, arg1, arg2);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Arg1 arg1; Arg2 arg2;
+};
+template <typename T, typename FunctionPointer, typename Class, typename Arg1, typename Arg2>
+class StoredInterfaceMemberFunctionCall2 : public QRunnable
+{
+public:
+ StoredInterfaceMemberFunctionCall2(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2), Class *object, const Arg1 &arg1, const Arg2 &arg2)
+ : fn(fn), object(object), arg1(arg1), arg2(arg2) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ (object->*fn)(futureInterface, arg1, arg2);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Class *object;
+ Arg1 arg1; Arg2 arg2;
+};
+
+template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3>
+class StoredInterfaceFunctionCall3 : public QRunnable
+{
+public:
+ StoredInterfaceFunctionCall3(void (fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3)
+ : fn(fn), arg1(arg1), arg2(arg2), arg3(arg3) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ fn(futureInterface, arg1, arg2, arg3);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Arg1 arg1; Arg2 arg2; Arg3 arg3;
+};
+template <typename T, typename FunctionPointer, typename Class, typename Arg1, typename Arg2, typename Arg3>
+class StoredInterfaceMemberFunctionCall3 : public QRunnable
+{
+public:
+ StoredInterfaceMemberFunctionCall3(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3)
+ : fn(fn), object(object), arg1(arg1), arg2(arg2), arg3(arg3) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ (object->*fn)(futureInterface, arg1, arg2, arg3);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Class *object;
+ Arg1 arg1; Arg2 arg2; Arg3 arg3;
+};
+
+template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+class StoredInterfaceFunctionCall4 : public QRunnable
+{
+public:
+ StoredInterfaceFunctionCall4(void (fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4)
+ : fn(fn), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ fn(futureInterface, arg1, arg2, arg3, arg4);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4;
+};
+template <typename T, typename FunctionPointer, typename Class, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+class StoredInterfaceMemberFunctionCall4 : public QRunnable
+{
+public:
+ StoredInterfaceMemberFunctionCall4(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4)
+ : fn(fn), object(object), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ (object->*fn)(futureInterface, arg1, arg2, arg3, arg4);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Class *object;
+ Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4;
+};
+
+template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
+class StoredInterfaceFunctionCall5 : public QRunnable
+{
+public:
+ StoredInterfaceFunctionCall5(void (fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5)
+ : fn(fn), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4), arg5(arg5) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ fn(futureInterface, arg1, arg2, arg3, arg4, arg5);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; Arg5 arg5;
+};
+template <typename T, typename FunctionPointer, typename Class, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
+class StoredInterfaceMemberFunctionCall5 : public QRunnable
+{
+public:
+ StoredInterfaceMemberFunctionCall5(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5)
+ : fn(fn), object(object), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4), arg5(arg5) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ (object->*fn)(futureInterface, arg1, arg2, arg3, arg4, arg5);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Class *object;
+ Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; Arg5 arg5;
+};
+
+template <typename T>
+QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &))
+{
+ return (new StoredInterfaceFunctionCall0<T, void (*)(QFutureInterface<T> &)>(functionPointer))->start();
+}
+template <typename T, typename Arg1>
+QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &, Arg1), const Arg1 &arg1)
+{
+ return (new StoredInterfaceFunctionCall1<T, void (*)(QFutureInterface<T> &, Arg1), Arg1>(functionPointer, arg1))->start();
+}
+template <typename T, typename Arg1, typename Arg2>
+QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &, Arg1, Arg2), const Arg1 &arg1, const Arg2 &arg2)
+{
+ return (new StoredInterfaceFunctionCall2<T, void (*)(QFutureInterface<T> &, Arg1, Arg2), Arg1, Arg2>(functionPointer, arg1, arg2))->start();
+}
+template <typename T, typename Arg1, typename Arg2, typename Arg3>
+QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &, Arg1, Arg2, Arg3), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3)
+{
+ return (new StoredInterfaceFunctionCall3<T, void (*)(QFutureInterface<T> &, Arg1, Arg2, Arg3), Arg1, Arg2, Arg3>(functionPointer, arg1, arg2, arg3))->start();
+}
+template <typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4)
+{
+ return (new StoredInterfaceFunctionCall4<T, void (*)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), Arg1, Arg2, Arg3, Arg4>(functionPointer, arg1, arg2, arg3, arg4))->start();
+}
+template <typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
+QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5)
+{
+ return (new StoredInterfaceFunctionCall5<T, void (*)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), Arg1, Arg2, Arg3, Arg4, Arg5>(functionPointer, arg1, arg2, arg3, arg4, arg5))->start();
+}
+
+template <typename Class, typename T>
+QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &), Class *object)
+{
+ return (new StoredInterfaceMemberFunctionCall0<T, void (Class::*)(QFutureInterface<T> &), Class>(fn, object))->start();
+}
+
+template <typename Class, typename T, typename Arg1>
+QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &, Arg1), Class *object, Arg1 arg1)
+{
+ return (new StoredInterfaceMemberFunctionCall1<T, void (Class::*)(QFutureInterface<T> &, Arg1), Class, Arg1>(fn, object, arg1))->start();
+}
+
+template <typename Class, typename T, typename Arg1, typename Arg2>
+QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2), Class *object, const Arg1 &arg1, const Arg2 &arg2)
+{
+ return (new StoredInterfaceMemberFunctionCall2<T, void (Class::*)(QFutureInterface<T> &, Arg1, Arg2), Class, Arg1, Arg2>(fn, object, arg1, arg2))->start();
+}
+
+template <typename Class, typename T, typename Arg1, typename Arg2, typename Arg3>
+QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3)
+{
+ return (new StoredInterfaceMemberFunctionCall3<T, void (Class::*)(QFutureInterface<T> &, Arg1, Arg2, Arg3), Class, Arg1, Arg2, Arg3>(fn, object, arg1, arg2, arg3))->start();
+}
+
+template <typename Class, typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4)
+{
+ return (new StoredInterfaceMemberFunctionCall4<T, void (Class::*)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), Class, Arg1, Arg2, Arg3, Arg4>(fn, object, arg1, arg2, arg3, arg4))->start();
+}
+
+template <typename Class, typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
+QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5)
+{
+ return (new StoredInterfaceMemberFunctionCall5<T, void (Class::*)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), Class, Arg1, Arg2, Arg3, Arg4, Arg5>(fn, object, arg1, arg2, arg3, arg4, arg5))->start();
+}
+} // namespace QtConcurrent
+
+QT_END_NAMESPACE
+
+#endif // QTCONCURRENT_RUNEX_H
diff --git a/src/libs/installer/settings.cpp b/src/libs/installer/settings.cpp
index 7d8f234cf..90cb431f4 100644
--- a/src/libs/installer/settings.cpp
+++ b/src/libs/installer/settings.cpp
@@ -230,7 +230,7 @@ Settings Settings::fromFileAndPrefix(const QString &path, const QString &prefix,
<< scStartMenuDir << scUninstallerName << scUninstallerIniFile << scRemoveTargetDir
<< scRunProgram << scRunProgramArguments << scRunProgramDescription
<< scDependsOnLocalInstallerBinary
- << scAllowSpaceInPath << scAllowNonAsciiCharacters
+ << scAllowSpaceInPath << scAllowNonAsciiCharacters << scWizardStyle << scTitleColor
<< scRepositorySettingsPageVisible << scTargetConfigurationFile
<< scRemoteRepositories << scTranslations;
@@ -344,6 +344,16 @@ QString Settings::icon() const
return d->makeAbsolutePath(d->m_data.value(scIcon).toString() + systemIconSuffix());
}
+QString Settings::wizardStyle() const
+{
+ return d->m_data.value(scWizardStyle).toString();
+}
+
+QString Settings::titleColor() const
+{
+ return d->m_data.value(scTitleColor).toString();
+}
+
QString Settings::installerApplicationIcon() const
{
return d->makeAbsolutePath(d->m_data.value(scInstallerApplicationIcon).toString() + systemIconSuffix());
diff --git a/src/libs/installer/settings.h b/src/libs/installer/settings.h
index a86b5f5fc..9bce8bd70 100644
--- a/src/libs/installer/settings.h
+++ b/src/libs/installer/settings.h
@@ -100,6 +100,8 @@ public:
QString installerApplicationIcon() const;
QString installerWindowIcon() const;
QString systemIconSuffix() const;
+ QString wizardStyle() const;
+ QString titleColor() const;
QString applicationName() const;
QString applicationVersion() const;
diff --git a/src/libs/installer/unziptask.cpp b/src/libs/installer/unziptask.cpp
new file mode 100644
index 000000000..b3a0b6bb2
--- /dev/null
+++ b/src/libs/installer/unziptask.cpp
@@ -0,0 +1,304 @@
+/**************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+#include "unziptask.h"
+
+#ifdef Q_OS_UNIX
+# include "StdAfx.h"
+#endif
+#include "Common/ComTry.h"
+// TODO: include once we switch from lib7z_fascade.h
+//#include "Common/MyInitGuid.h"
+
+#include "7zip/IPassword.h"
+#include "7zip/Common/FileStreams.h"
+#include "7zip/UI/Common/OpenArchive.h"
+
+#include "Windows/FileDir.h"
+#include "Windows/PropVariant.h"
+
+#include "7zCrc.h"
+
+#include <QDir>
+
+void registerArc7z();
+void registerCodecLZMA();
+void registerCodecLZMA2();
+
+namespace QInstaller {
+
+class ArchiveExtractCallback : public IArchiveExtractCallback, public CMyUnknownImp
+{
+public:
+ MY_UNKNOWN_IMP
+ ArchiveExtractCallback(const QString &target, const CArc &arc, QFutureInterface<QString> &fi)
+ : m_target(target)
+ , m_arc(arc)
+ {
+ m_futureInterface = &fi;
+ }
+
+
+ // -- IProgress
+
+ STDMETHOD(SetTotal)(UInt64 total)
+ {
+ COM_TRY_BEGIN
+ m_totalUnpacked = 0;
+ m_totalUnpackedExpected = total;
+ return S_OK;
+ COM_TRY_END
+ }
+
+ STDMETHOD(SetCompleted)(const UInt64 *completeValue)
+ {
+ COM_TRY_BEGIN
+ Q_UNUSED(completeValue)
+ return S_OK; // return S_OK here as we do not support sub archive extracting
+ COM_TRY_END
+ }
+
+
+ // -- IArchiveExtractCallback
+
+ STDMETHOD(GetStream)(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode)
+ {
+ if (m_futureInterface->isCanceled())
+ return E_FAIL;
+ if (m_futureInterface->isPaused())
+ m_futureInterface->waitForResume();
+
+ COM_TRY_BEGIN
+ *outStream = 0;
+ m_currentIndex = index;
+ if (askExtractMode != NArchive::NExtract::NAskMode::kExtract)
+ return E_FAIL;
+
+ bool isDir = false;
+ if (IsArchiveItemFolder(m_arc.Archive, m_currentIndex, isDir) != S_OK)
+ return E_FAIL;
+
+ bool isEncrypted = false;
+ if (GetArchiveItemBoolProp(m_arc.Archive, m_currentIndex, kpidEncrypted, isEncrypted) != S_OK)
+ return E_FAIL;
+
+ if (isDir || isEncrypted)
+ return E_FAIL;
+
+ UString itemPath;
+ if (m_arc.GetItemPath(m_currentIndex, itemPath) != S_OK)
+ return E_FAIL;
+
+ QDir().mkpath(m_target);
+ m_currentTarget = m_target + QLatin1Char('/') + QString::fromStdWString((const wchar_t*)(itemPath))
+ .replace(QLatin1Char('\\'), QLatin1Char('/'));
+
+ m_outFileStream = new COutFileStream;
+ CMyComPtr<ISequentialOutStream> scopedPointer(m_outFileStream);
+ if (!m_outFileStream->Open((wchar_t*)(m_currentTarget.utf16()), CREATE_ALWAYS))
+ return E_FAIL;
+
+ m_outFileStreamComPtr = scopedPointer;
+ *outStream = scopedPointer.Detach();
+
+ return S_OK;
+ COM_TRY_END
+ }
+
+ STDMETHOD(PrepareOperation)(Int32 askExtractMode)
+ {
+ COM_TRY_BEGIN
+ Q_UNUSED(askExtractMode)
+ m_futureInterface->setProgressValueAndText(0, QLatin1String("Started to extract archive."));
+ return S_OK; // return S_OK here as we do not need to prepare anything
+ COM_TRY_END
+ }
+
+ STDMETHOD(SetOperationResult)(Int32 resultEOperationResult)
+ {
+ COM_TRY_BEGIN
+ switch (resultEOperationResult)
+ {
+ case NArchive::NExtract::NOperationResult::kOK:
+ break;
+
+ default: // fall through and bail
+ case NArchive::NExtract::NOperationResult::kCRCError:
+ case NArchive::NExtract::NOperationResult::kDataError:
+ case NArchive::NExtract::NOperationResult::kUnSupportedMethod:
+ m_outFileStream->Close();
+ m_outFileStreamComPtr.Release();
+ return E_FAIL;
+ }
+
+ UInt32 attributes;
+ if (GetAttributes(&attributes))
+ NWindows::NFile::NDirectory::MySetFileAttributes((wchar_t*)(m_currentTarget.utf16()), attributes);
+
+ FILETIME accessTime, creationTime, modificationTime;
+ const bool writeAccessTime = GetTime(kpidATime, &accessTime);
+ const bool writeCreationTime = GetTime(kpidCTime, &creationTime);
+ const bool writeModificationTime = GetTime(kpidMTime, &modificationTime);
+
+ m_outFileStream->SetTime((writeCreationTime ? &creationTime : NULL),
+ (writeAccessTime ? &accessTime : NULL), (writeModificationTime ? &modificationTime : NULL));
+
+ m_totalUnpacked += m_outFileStream->ProcessedSize;
+ m_outFileStream->Close();
+ m_outFileStreamComPtr.Release();
+
+ m_futureInterface->reportResult(m_currentTarget);
+ m_futureInterface->setProgressValueAndText(100 * m_totalUnpacked / m_totalUnpackedExpected,
+ m_currentTarget);
+ return S_OK;
+ COM_TRY_END
+ }
+
+private:
+ bool GetAttributes(UInt32 *attributes) const
+ {
+ *attributes = 0;
+ NWindows::NCOM::CPropVariant property;
+ if (m_arc.Archive->GetProperty(m_currentIndex, kpidAttrib, &property) != S_OK)
+ return false;
+
+ if (property.vt != VT_UI4)
+ return false;
+
+ *attributes = property.ulVal;
+ return (property.vt == VT_UI4);
+ }
+
+ bool GetTime(PROPID propertyId, FILETIME *filetime) const
+ {
+ if (!filetime)
+ return false;
+
+ filetime->dwLowDateTime = 0;
+ filetime->dwHighDateTime = 0;
+
+ NWindows::NCOM::CPropVariant property;
+ if (m_arc.Archive->GetProperty(m_currentIndex, propertyId, &property) != S_OK)
+ return false;
+
+ if (property.vt != VT_FILETIME)
+ return false;
+
+ *filetime = property.filetime;
+ return (filetime->dwHighDateTime != 0 || filetime->dwLowDateTime != 0);
+ }
+
+private:
+ QString m_target;
+ const CArc &m_arc;
+ UnzipTask *m_unzipTask;
+ QFutureInterface<QString> *m_futureInterface;
+
+ UInt32 m_currentIndex;
+ QString m_currentTarget;
+
+ UInt64 m_totalUnpacked;
+ UInt64 m_totalUnpackedExpected;
+
+ COutFileStream *m_outFileStream;
+ CMyComPtr<ISequentialOutStream> m_outFileStreamComPtr;
+};
+
+
+// -- UnzipTask
+
+UnzipTask::UnzipTask(const QString &source, const QString &target)
+ : m_source(source)
+ , m_target(target)
+{
+ {
+ CrcGenerateTable();
+
+ registerArc7z();
+ registerCodecLZMA();
+ registerCodecLZMA2();
+ }
+}
+
+void UnzipTask::doTask(QFutureInterface<QString> &fi)
+{
+ fi.reportStarted();
+
+ CCodecs codecs;
+ if (codecs.Load() != S_OK)
+ return;
+
+ CIntVector formatIndices;
+ if (!codecs.FindFormatForArchiveType(L"", formatIndices))
+ return;
+
+ CInFileStream *fileStream = new CInFileStream;
+ fileStream->Open((wchar_t*) (m_source.utf16()));
+
+ CArchiveLink archiveLink;
+ if (archiveLink.Open2(&codecs, formatIndices, false, fileStream, UString(), 0) != S_OK)
+ return;
+
+ UINT32 count = 0;
+ for (int i = 0; i < archiveLink.Arcs.Size(); ++i) {
+ const CArc& arc = archiveLink.Arcs[i];
+ UInt32 numItems = 0;
+ if (arc.Archive->GetNumberOfItems(&numItems) != S_OK)
+ break;
+ count += numItems;
+ }
+ fi.setExpectedResultCount(count);
+
+ for (int i = 0; i < archiveLink.Arcs.Size(); ++i) {
+ if (fi.isCanceled())
+ break;
+ if (fi.isPaused())
+ fi.waitForResume();
+
+ const UInt32 extractAll = UInt32(-1);
+ const CArc &arc = archiveLink.Arcs[i];
+ arc.Archive->Extract(0, extractAll, NArchive::NExtract::NAskMode::kExtract,
+ new ArchiveExtractCallback(m_target, arc, fi));
+ }
+
+ fi.reportFinished();
+}
+
+} // namespace QInstaller
diff --git a/src/libs/installer/unziptask.h b/src/libs/installer/unziptask.h
new file mode 100644
index 000000000..40e1c6722
--- /dev/null
+++ b/src/libs/installer/unziptask.h
@@ -0,0 +1,70 @@
+/**************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+
+#ifndef UNZIPTASK_H
+#define UNZIPTASK_H
+
+#include "abstracttask.h"
+#include "installer_global.h"
+
+namespace QInstaller {
+
+class INSTALLER_EXPORT UnzipTask : public AbstractTask<QString>
+{
+public:
+ UnzipTask() {}
+ UnzipTask(const QString &source, const QString &target);
+
+ void doTask(QFutureInterface<QString> &fi);
+
+private:
+ void setBytesToExtract(qint64 bytes);
+ void addBytesExtracted(qint64 bytes);
+
+private:
+ QString m_source;
+ QString m_target;
+ friend class ArchiveExtractCallback;
+};
+
+} // namespace QInstaller
+
+#endif // UNZIPTASK_H
diff --git a/src/libs/kdtools/kdsavefile.cpp b/src/libs/kdtools/kdsavefile.cpp
index 88b95f42e..8e2209604 100644
--- a/src/libs/kdtools/kdsavefile.cpp
+++ b/src/libs/kdtools/kdsavefile.cpp
@@ -54,7 +54,7 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
-#ifdef Q_OS_LINUX
+#ifdef Q_OS_UNIX
#include <unistd.h>
#endif
@@ -174,11 +174,10 @@ static QFile *createFile(const QString &path, QIODevice::OpenMode m, QFile::Perm
*/
static QString generateTempFileName(const QString &path)
{
- const QString tmp = path + QLatin1String("tmp.dsfdf.%1"); //TODO: use random suffix
- int count = 1;
- while (QFile::exists(tmp.arg(count)))
- ++count;
- return tmp.arg(count);
+ QTemporaryFile tmpfile(path);
+ tmpfile.open();
+ const QString tmp = tmpfile.fileName();
+ return tmp;
}
/*!
@@ -384,7 +383,7 @@ bool KDSaveFile::commit(KDSaveFile::CommitMode mode)
}
if (mode == OverwriteExistingFile) {
QFile tmp(backup);
- const bool removed = !tmp.exists() || tmp.remove(backup);
+ const bool removed = !tmp.exists() || tmp.remove();
if (!removed)
qWarning() << "Could not remove the backup: " << tmp.errorString();
}
diff --git a/src/libs/kdtools/kdsysinfo.cpp b/src/libs/kdtools/kdsysinfo.cpp
index 98a0d951e..46192e742 100644
--- a/src/libs/kdtools/kdsysinfo.cpp
+++ b/src/libs/kdtools/kdsysinfo.cpp
@@ -66,7 +66,7 @@ VolumeInfo VolumeInfo::fromPath(const QString &path)
QList<VolumeInfo> volumes = mountedVolumes();
// sort by length to get the longest mount point (not just "/") first
- qSort(volumes.begin(), volumes.end(), PathLongerThan());
+ std::sort(volumes.begin(), volumes.end(), PathLongerThan());
foreach (const VolumeInfo &volume, volumes) {
const QDir volumePath(volume.mountPath());
if (targetPath == volumePath)
diff --git a/src/libs/kdtools/kdupdaterupdatesourcesinfo.cpp b/src/libs/kdtools/kdupdaterupdatesourcesinfo.cpp
index 9acd09682..140577d3c 100644
--- a/src/libs/kdtools/kdupdaterupdatesourcesinfo.cpp
+++ b/src/libs/kdtools/kdupdaterupdatesourcesinfo.cpp
@@ -250,7 +250,7 @@ void UpdateSourcesInfo::addUpdateSourceInfo(const UpdateSourceInfo &info)
if (d->updateSourceInfoList.contains(info))
return;
d->updateSourceInfoList.push_back(info);
- qSort(d->updateSourceInfoList.begin(), d->updateSourceInfoList.end(), UpdateSourceInfoPriorityHigherThan());
+ std::sort(d->updateSourceInfoList.begin(), d->updateSourceInfoList.end(), UpdateSourceInfoPriorityHigherThan());
emit updateSourceInfoAdded(info);
d->modified = true;
}
diff --git a/src/sdk/installerbasecommons.cpp b/src/sdk/installerbasecommons.cpp
index 0cf85a0ec..263eb5767 100644
--- a/src/sdk/installerbasecommons.cpp
+++ b/src/sdk/installerbasecommons.cpp
@@ -116,6 +116,7 @@ IntroductionPageImpl::IntroductionPageImpl(QInstaller::PackageManagerCore *core)
core->setCompleteUninstallation(core->isUninstaller());
+ connect(core, SIGNAL(metaJobProgress(int)), this, SLOT(onProgressChanged(int)));
connect(core, SIGNAL(metaJobInfoMessage(QString)), this, SLOT(setMessage(QString)));
connect(core, SIGNAL(coreNetworkSettingsChanged()), this, SLOT(onCoreNetworkSettingsChanged()));
@@ -249,6 +250,12 @@ void IntroductionPageImpl::setMessage(const QString &msg)
m_label->setText(msg);
}
+void IntroductionPageImpl::onProgressChanged(int progress)
+{
+ m_progressBar->setRange(0, 100);
+ m_progressBar->setValue(progress);
+}
+
void IntroductionPageImpl::setErrorMessage(const QString &error)
{
QPalette palette;
@@ -335,6 +342,8 @@ void IntroductionPageImpl::entering()
setErrorMessage(QString());
setButtonText(QWizard::CancelButton, tr("Quit"));
+ m_progressBar->setValue(0);
+ m_progressBar->setRange(0, 0);
PackageManagerCore *core = packageManagerCore();
if (core->isUninstaller() ||core->isUpdater() || core->isPackageManager()) {
showMaintenanceTools();
@@ -345,6 +354,8 @@ void IntroductionPageImpl::entering()
void IntroductionPageImpl::leaving()
{
+ m_progressBar->setValue(0);
+ m_progressBar->setRange(0, 0);
setButtonText(QWizard::CancelButton, gui()->defaultButtonText(QWizard::CancelButton));
}
@@ -388,6 +399,19 @@ QString TargetDirectoryPageImpl::targetDirWarning() const
"absolute path.");
}
+ QDir target(targetDir());
+ target = target.canonicalPath();
+
+ if (target.isRoot()) {
+ return TargetDirectoryPageImpl::tr("As the install directory is completely deleted, installing "
+ "in %1 is forbidden.").arg(QDir::toNativeSeparators(QDir::rootPath()));
+ }
+
+ if (target == QDir::home()) {
+ return TargetDirectoryPageImpl::tr("As the install directory is completely deleted, installing "
+ "in %1 is forbidden.").arg(QDir::toNativeSeparators(QDir::homePath()));
+ }
+
QString dir = QDir::toNativeSeparators(targetDir());
#ifdef Q_OS_WIN
// folder length (set by user) + maintenance tool name length (no extension) + extra padding
@@ -468,11 +492,6 @@ bool TargetDirectoryPageImpl::validatePage()
const QFileInfo fi(targetDir);
if (fi.isDir()) {
- if (dir == QDir::root() || dir == QDir::home()) {
- return failWithError(QLatin1String("ForbiddenTargetDirectory"), tr("As the install directory "
- "is completely deleted installing in %1 is forbidden.").arg(QDir::rootPath()));
- }
-
QString fileName = packageManagerCore()->settings().uninstallerName();
#if defined(Q_OS_MAC)
if (QFileInfo(QCoreApplication::applicationDirPath() + QLatin1String("/../..")).isBundle())
diff --git a/src/sdk/installerbasecommons.h b/src/sdk/installerbasecommons.h
index 2bcdce3f2..79330eaf7 100644
--- a/src/sdk/installerbasecommons.h
+++ b/src/sdk/installerbasecommons.h
@@ -72,6 +72,7 @@ public:
public Q_SLOTS:
void onCoreNetworkSettingsChanged();
void setMessage(const QString &msg);
+ void onProgressChanged(int progress);
void setErrorMessage(const QString &error);
Q_SIGNALS:
diff --git a/src/sdk/sdk.pro b/src/sdk/sdk.pro
index 67fd77f2a..e75fbe3c2 100644
--- a/src/sdk/sdk.pro
+++ b/src/sdk/sdk.pro
@@ -8,6 +8,12 @@ QT += network script xml
isEqual(QT_MAJOR_VERSION, 5) {
QT += widgets
+ # add the minimal plugin in static case to be able to start the installer
+ # headless with: installer-binary -platform minimal
+ # using QT += qpa_minimal_plugin would result in a minimal only compiled version
+ !win32:CONFIG(static, static|shared) {
+ QTPLUGIN += qminimal
+ }
}
DESTDIR = $$IFW_APP_PATH
diff --git a/src/sdk/settingsdialog.h b/src/sdk/settingsdialog.h
index a2386acbb..942adfc2f 100644
--- a/src/sdk/settingsdialog.h
+++ b/src/sdk/settingsdialog.h
@@ -53,16 +53,16 @@ QT_BEGIN_NAMESPACE
class QAuthenticator;
class QLocale;
class QVariant;
+
+namespace Ui {
+ class SettingsDialog;
+}
QT_END_NAMESPACE
namespace QInstaller {
class PackageManagerCore;
}
-namespace Ui {
- class SettingsDialog;
-}
-
// -- PasswordDelegate
class PasswordDelegate : public QStyledItemDelegate
diff --git a/tests/auto/installer/installer.pro b/tests/auto/installer/installer.pro
index f4c4bbaf4..c565561b4 100644
--- a/tests/auto/installer/installer.pro
+++ b/tests/auto/installer/installer.pro
@@ -15,4 +15,5 @@ SUBDIRS += \
solver \
binaryformat \
packagemanagercore \
- settingsoperation
+ settingsoperation \
+ task
diff --git a/tests/auto/installer/settings/data/full_config.xml b/tests/auto/installer/settings/data/full_config.xml
index 0386f98c1..8af96edda 100644
--- a/tests/auto/installer/settings/data/full_config.xml
+++ b/tests/auto/installer/settings/data/full_config.xml
@@ -21,6 +21,7 @@ File should contain all elements we allow in a config.xml
<Watermark>watermark</Watermark>
<Banner>banner</Banner>
<Background>background</Background>
+ <WizardStyle>Modern</WizardStyle>
<StartMenuDir>Super App</StartMenuDir>
diff --git a/tests/auto/installer/task/task.pro b/tests/auto/installer/task/task.pro
new file mode 100644
index 000000000..ff41f5cce
--- /dev/null
+++ b/tests/auto/installer/task/task.pro
@@ -0,0 +1,8 @@
+include(../../qttest.pri)
+
+QT -= gui
+QT += network
+isEqual(QT_MAJOR_VERSION, 5) {
+ QT += concurrent
+}
+SOURCES += tst_task.cpp
diff --git a/tests/auto/installer/task/tst_task.cpp b/tests/auto/installer/task/tst_task.cpp
new file mode 100644
index 000000000..a966671ac
--- /dev/null
+++ b/tests/auto/installer/task/tst_task.cpp
@@ -0,0 +1,131 @@
+/**************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+
+#include <copyfiletask.h>
+#include <downloadfiletask.h>
+#include <fileutils.h>
+
+#include <QFutureWatcher>
+#include <QSignalSpy>
+#include <QTest>
+#include <QTemporaryFile>
+
+using namespace QInstaller;
+
+static const qint64 scLargeSize = 4194304LL;
+
+class tst_Task : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void copyFile()
+ {
+ QTemporaryFile file;
+ file.setAutoRemove(false);
+
+ if (file.open()) {
+ const QString filename = file.fileName();
+ QInstaller::blockingWrite(&file, QByteArray(scLargeSize, '1'));
+ file.close();
+
+ CopyFileTask fileTask(filename);
+ QFutureWatcher<FileTaskResult> watcher;
+
+ QSignalSpy started(&watcher, SIGNAL(started()));
+ QSignalSpy finished(&watcher, SIGNAL(finished()));
+ QSignalSpy progress(&watcher, SIGNAL(progressValueChanged(int)));
+
+ watcher.setFuture(QtConcurrent::run(&CopyFileTask::doTask, &fileTask));
+
+ watcher.waitForFinished();
+ QTest::qWait(10); // Spin the event loop to deliver queued signals.
+
+ QCOMPARE(started.count(), 1);
+ QCOMPARE(finished.count(), 1);
+
+ FileTaskResult result = watcher.result();
+ QCOMPARE(watcher.future().resultCount(), 1);
+
+ QVERIFY(QFile(result.target()).exists());
+ QCOMPARE(file.size(), QFile(result.target()).size());
+ QCOMPARE(result.checkSum().toHex(), QByteArray("85304f87b8d90554a63c6f6d1e9cc974fbef8d32"));
+ }
+ }
+
+ void downloadFile()
+ {
+ QTemporaryFile file;
+ file.setAutoRemove(false);
+
+ if (file.open()) {
+ const QString filename = file.fileName();
+ QInstaller::blockingWrite(&file, QByteArray(scLargeSize, '1'));
+ file.close();
+
+ DownloadFileTask fileTask(QLatin1String("file:///") + filename);
+ QFutureWatcher<FileTaskResult> watcher;
+
+ QSignalSpy started(&watcher, SIGNAL(started()));
+ QSignalSpy finished(&watcher, SIGNAL(finished()));
+ QSignalSpy progress(&watcher, SIGNAL(progressValueChanged(int)));
+
+ watcher.setFuture(QtConcurrent::run(&DownloadFileTask::doTask, &fileTask));
+
+ watcher.waitForFinished();
+ QTest::qWait(10); // Spin the event loop to deliver queued signals.
+
+ QCOMPARE(started.count(), 1);
+ QCOMPARE(finished.count(), 1);
+
+ FileTaskResult result = watcher.result();
+ QCOMPARE(watcher.future().resultCount(), 1);
+
+ QVERIFY(QFile(result.target()).exists());
+ QCOMPARE(file.size(), QFile(result.target()).size());
+ QCOMPARE(result.checkSum().toHex(), QByteArray("85304f87b8d90554a63c6f6d1e9cc974fbef8d32"));
+ }
+ }
+};
+
+QTEST_MAIN(tst_Task)
+
+#include "tst_task.moc"
diff --git a/tools/build_installer.py b/tools/build_installer.py
index a301c6f48..a301c6f48 100644..100755
--- a/tools/build_installer.py
+++ b/tools/build_installer.py
diff --git a/tools/common/repositorygen.cpp b/tools/common/repositorygen.cpp
index 609844829..77ce8eb6f 100644
--- a/tools/common/repositorygen.cpp
+++ b/tools/common/repositorygen.cpp
@@ -446,8 +446,14 @@ PackageInfoVector QInstallerTools::createListOfPackages(const QStringList &packa
"path element right before the 'meta' ('%2').").arg(fileInfo.absoluteFilePath(), it->fileName());
}
- const QString releaseDate = packageElement.firstChildElement(QLatin1String("ReleaseDate")).text();
- if (releaseDate.isEmpty() || (!QDate::fromString(releaseDate, Qt::ISODate).isValid())) {
+ QString releaseDate = packageElement.firstChildElement(QLatin1String("ReleaseDate")).text();
+ if (releaseDate.isEmpty()) {
+ qWarning("Release date for '%s' is empty! Using the current date instead.",
+ qPrintable(fileInfo.absoluteFilePath()));
+ releaseDate = QDate::currentDate().toString(Qt::ISODate);
+ }
+
+ if (!QDate::fromString(releaseDate, Qt::ISODate).isValid()) {
if (ignoreInvalidPackages)
continue;
throw QInstaller::Error(QString::fromLatin1("Release date for '%1' is invalid! <ReleaseDate>%2"
diff --git a/tools/getrepositorycontent/main.cpp b/tools/getrepositorycontent/main.cpp
index c84826359..148280e3f 100644
--- a/tools/getrepositorycontent/main.cpp
+++ b/tools/getrepositorycontent/main.cpp
@@ -69,10 +69,11 @@ static void printUsage()
const QString appName = QFileInfo( QCoreApplication::applicationFilePath() ).fileName();
std::cout << "Usage: " << qPrintable(appName)
<< " --url <repository_url> --repository <empty_repository_dir> --packages <empty_packages_dir>" << std::endl;
- std::cout << " --url URL to fetch all the content from." << std::endl;
- std::cout << " --repository Target directory for the repository content." << std::endl;
- std::cout << " --packages The packages target directory where it creates the needed content to create new installers or repositories." << std::endl;
- std::cout << " --clean Removes all the content if there is an existing repository or packages dir" << std::endl;
+ std::cout << " --url URL to fetch all the content from." << std::endl;
+ std::cout << " --repository Target directory for the repository content." << std::endl;
+ std::cout << " --packages The packages target directory where it creates the needed content to create new installers or repositories." << std::endl;
+ std::cout << " --clean Removes all the content if there is an existing repository or packages dir" << std::endl;
+ std::cout << " --only-metacontent Download only the meta content of the components." << std::endl;
std::cout << "Example:" << std::endl;
std::cout << " " << qPrintable(appName) << " --url http://www.example.com/repository/" <<
@@ -196,8 +197,12 @@ QHash<QString, ComponentData> downLoadRepository(const QString &repositoryUrl, c
QStringList tDownloadList = packageUpdateEntry.toElement().text().split(
QInstaller::commaRegExp(), QString::SkipEmptyParts);
foreach (const QString &download, tDownloadList) {
- currentComponentData.m_downloadDownloadableArchives.append(
- currentComponentData.m_version + download);
+ if (qApp->arguments().contains(QLatin1String("--only-metacontent"))) {
+ qDebug() << "Skip download: <url> + " << currentPackageName + QLatin1String("/") + currentComponentData.m_version + download;
+ } else {
+ currentComponentData.m_downloadDownloadableArchives.append(
+ currentComponentData.m_version + download);
+ }
currentComponentData.m_downloadDownloadableArchives.append(
currentComponentData.m_version + download + QLatin1String(".sha1"));
}
@@ -283,6 +288,8 @@ int main(int argc, char *argv[])
if (*itArgument == QString::fromLatin1("-h") || *itArgument == QString::fromLatin1("--help")) {
printUsage();
return 0;
+ } else if (*itArgument == QString::fromLatin1("--only-metacontent")) {
+ // just consume that argument, it will be used later via qApp->arguments
} else if (*itArgument == QString::fromLatin1("--clean")) {
clean = true;
} else if (*itArgument == QString::fromLatin1("-u") || *itArgument == QString::fromLatin1("--url")) {