summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/images/ifw-repository-categories.pngbin0 -> 58532 bytes
-rw-r--r--doc/includes/installerfw-examples-generating-online.qdocinc18
-rw-r--r--doc/installerfw.qdoc34
-rw-r--r--examples/doc/images/qtifw-examples-repository-categories.pngbin0 -> 58532 bytes
-rw-r--r--examples/doc/repositorycategories.qdoc117
-rw-r--r--examples/examples.pro1
-rw-r--r--examples/repositorycategories/README30
-rw-r--r--examples/repositorycategories/config/config.xml33
-rw-r--r--examples/repositorycategories/packages/A/data/A.txt2
-rw-r--r--examples/repositorycategories/packages/A/meta/package.xml8
-rw-r--r--examples/repositorycategories/packages/B/data/B.txt2
-rw-r--r--examples/repositorycategories/packages/B/meta/package.xml8
-rw-r--r--examples/repositorycategories/packages2_forcategory1/A2Cagetory1/data/A2_category1.txt2
-rw-r--r--examples/repositorycategories/packages2_forcategory1/A2Cagetory1/meta/package.xml8
-rw-r--r--examples/repositorycategories/packages2_forcategory1/B2Category1/data/B2_category1.txt2
-rw-r--r--examples/repositorycategories/packages2_forcategory1/B2Category1/meta/package.xml8
-rw-r--r--examples/repositorycategories/packages_forcategory1/ACagetory1/data/A_category1.txt2
-rw-r--r--examples/repositorycategories/packages_forcategory1/ACagetory1/meta/package.xml8
-rw-r--r--examples/repositorycategories/packages_forcategory1/BCategory1/data/B_category1.txt2
-rw-r--r--examples/repositorycategories/packages_forcategory1/BCategory1/meta/package.xml8
-rw-r--r--examples/repositorycategories/packages_forcategory2/ACategory2/data/A_category2.txt2
-rw-r--r--examples/repositorycategories/packages_forcategory2/ACategory2/meta/package.xml8
-rw-r--r--examples/repositorycategories/packages_forcategory2/BCategory2/data/B_category2.txt2
-rw-r--r--examples/repositorycategories/packages_forcategory2/BCategory2/meta/package.xml8
-rw-r--r--examples/repositorycategories/repositorycategories.pro13
-rw-r--r--src/libs/installer/constants.h1
-rw-r--r--src/libs/installer/installer.pro6
-rw-r--r--src/libs/installer/metadatajob.cpp72
-rw-r--r--src/libs/installer/metadatajob.h15
-rw-r--r--src/libs/installer/packagemanagercore.cpp1
-rw-r--r--src/libs/installer/packagemanagercore_p.cpp4
-rw-r--r--src/libs/installer/packagemanagergui.cpp244
-rw-r--r--src/libs/installer/packagemanagergui.h1
-rw-r--r--src/libs/installer/repository.cpp22
-rw-r--r--src/libs/installer/repository.h4
-rw-r--r--src/libs/installer/repositorycategory.cpp159
-rw-r--r--src/libs/installer/repositorycategory.h86
-rw-r--r--src/libs/installer/settings.cpp60
-rw-r--r--src/libs/installer/settings.h6
39 files changed, 932 insertions, 75 deletions
diff --git a/doc/images/ifw-repository-categories.png b/doc/images/ifw-repository-categories.png
new file mode 100644
index 000000000..afed7c1b9
--- /dev/null
+++ b/doc/images/ifw-repository-categories.png
Binary files differ
diff --git a/doc/includes/installerfw-examples-generating-online.qdocinc b/doc/includes/installerfw-examples-generating-online.qdocinc
new file mode 100644
index 000000000..f623b1d22
--- /dev/null
+++ b/doc/includes/installerfw-examples-generating-online.qdocinc
@@ -0,0 +1,18 @@
+ \section1 Generating the Example Installer
+
+ To create the example installer, switch to the example source directory on
+ the command line and enter the following command:
+
+ \list
+ \li On Windows:
+ \code
+ ..\..\bin\binarycreator.exe --online-only -c config\config.xml -p packages installer.exe
+ \endcode
+ \li On Linux or macOS:
+ \code
+ ../../bin/binarycreator --online-only -c config/config.xml -p packages installer
+ \endcode
+ \endlist
+
+ You should now be able to run the installer and install from the repository.
+
diff --git a/doc/installerfw.qdoc b/doc/installerfw.qdoc
index 22a15983b..bdd99c089 100644
--- a/doc/installerfw.qdoc
+++ b/doc/installerfw.qdoc
@@ -266,6 +266,10 @@
elements that each contain the \c <Url> child element that specifies the URL to
access the repository. For more information, see \l{Configuring Repositories}.
\row
+ \li RepositoryCategories
+ \li Name of a category that can contain a list of \c <RemoteRepositories> child elements.
+ For more information, see \l{Configuring Repository Categories}.
+ \row
\li MaintenanceToolName
\li Filename of the generated maintenance tool. Defaults to
\e maintenancetool. The platform-specific executable file extension is
@@ -1114,6 +1118,36 @@
text. Authentication details not set here will be gotten at runtime using a dialog.
The user can work around these settings at runtime.
+ \section1 Configuring Repository Categories
+
+ The \c <RepositoryCategory> element in the installer configuration file
+ (config.xml) can contain a list of several \c <RemoteRepositories> elements. Each \c <RemoteRepositories>
+ element within the \c <RepositoryCagetory> element is considered a category, which has a \c <DisplayName> and can
+ contain several \c <Repository> elements. Repository categories are shown in the component selection page,
+ on the left side of the component selection widget:
+
+ \image ifw-repository-categories.png "Component selection Page"
+
+ By default, only repositories with no category are shown in the component selection widget. Checking one or
+ several repositories and pressing \uicontrol Fetch will update the widget to show content also
+ from the selected categorized repositories.
+
+ Example of creating a repository category:
+
+ \code
+ <RepositoryCategories>
+ <RemoteRepositories>
+ <Displayname>Category 1</Displayname>
+ <Repository>
+ <Url>http://www.example.com/packages</Url>
+ <Enabled>1</Enabled>
+ <Username>user</Username>
+ <Password>password</Password>
+ <DisplayName>Example repository</DisplayName>
+ </Repository>
+ </RemoteRepositories>
+ </RepositoryCategories>
+ \endcode
\section1 Creating Installer Binaries
diff --git a/examples/doc/images/qtifw-examples-repository-categories.png b/examples/doc/images/qtifw-examples-repository-categories.png
new file mode 100644
index 000000000..afed7c1b9
--- /dev/null
+++ b/examples/doc/images/qtifw-examples-repository-categories.png
Binary files differ
diff --git a/examples/doc/repositorycategories.qdoc b/examples/doc/repositorycategories.qdoc
new file mode 100644
index 000000000..dca5ada43
--- /dev/null
+++ b/examples/doc/repositorycategories.qdoc
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: http://www.gnu.org/copyleft/fdl.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example repositorycategories
+ \ingroup qtifwexamples
+ \title Repository Categories Example
+
+ \brief Using the RepositoryCategories element to set up an
+ online installer where repositories are grouped.
+
+ \image qtifw-examples-repository-categories.png
+
+ \e{Repository Categories} illustrates how to set up an installer
+ where repositories are grouped into categories.
+
+ \include installerfw-examples-configuring.qdocinc
+
+ \list
+ \li The \c <RepositoryCategories> element shows how to group repositories into categories.
+ \c <RepositoryCategories> can contain one or several \c <RemoteRepositories>
+ child elements that specify a connection to repositories. For more
+ information about \c <RemoteRepositories> see
+ \l{Configuring Repositories}.
+ \endlist
+
+ \quotefile repositorycategories/config/config.xml
+
+ \include installerfw-examples-packaging.qdocinc
+
+ \list
+ \li The \c <Default> element is set to \c true to preselect the
+ component in the installer.
+ \endlist
+
+ \quotefile online/packages/A/meta/package.xml
+
+ \section1 Generating the Online Repository
+
+ This installer contains four packages that each have two components. The \c Packages directory contains two components
+ that are not grouped categories. They are always visible in tree view in the component selection page. \c Packages_forcategory1
+ and \c packages2_forcategory1 both contain two components, which are visible when \c Category 1 is fetched. \c Packages_forcategory2
+ contains two components that are visible only when \c Category 2 is fetched.
+
+ The packages need to be converted to a file structure that the installer can
+ fetch at runtime. To use the \c repogen tool to convert the packages, switch
+ to the example source directory on the command line and enter the following
+ command:
+
+ \list
+ \li On Windows:
+ \code
+ ..\..\bin\repogen.exe -p packages repository
+ ..\..\bin\repogen.exe -p packages_forcategory1 repository1
+ ..\..\bin\repogen.exe -p packages2_forcategory1 repository2
+ ..\..\bin\repogen.exe -p packages_forcategory2 repository3
+ \endcode
+ \li On Linux or macOS:
+ \code
+ ../../bin/repogen -p packages repository
+ ../../bin/repogen -p packages_forcategory1 repository1
+ ../../bin/repogen -p packages2_forcategory1 repository2
+ ../../bin/repogen -p packages_forcategory2 repository3
+ \endcode
+ \endlist
+
+ The generated \c repository, \c repository1, \c repository2 and \c repository3 directories will now
+ contain a full copy of the package data and some additionally generated metadata, such as SHA
+ checksums.
+
+ The directories now need to be made available at the URL set in
+ \c config.xml: \c{http://localhost/repository}, \c{http://localhost/repository1}, \c{http://localhost/repository2} and
+ \c{http://localhost/repository3}. How this is done depends on
+ the platform and web server used. If you do not have a running web server
+ yet, but have Python available, you should be able to start a minimal web
+ server from the command line. Make sure you are in the example directory,
+ and then enter:
+
+ \code
+ python -m SimpleHTTPServer 80
+ \endcode
+
+ You should now be able to open and explore \l{http://localhost/repository}
+ in your web browser.
+
+ \note If you do not have enough permissions to set up a web server locally,
+ you can also specify an absolute \c{file:///} URL as the value of the \c URL
+ element in \c config.xml. For example,
+ \c file:///C:/Qt/QtIFW/examples/repositorycategories/repository would be a valid URL on
+ Windows if \c repository is located in \c C:\Qt\QtIFW\examples\repositorycategories.
+
+ \include installerfw-examples-generating-online.qdocinc
+*/
diff --git a/examples/examples.pro b/examples/examples.pro
index 377632b9c..bfe69a5c8 100644
--- a/examples/examples.pro
+++ b/examples/examples.pro
@@ -11,6 +11,7 @@ SUBDIRS += \
openreadme \
quitinstaller \
registerfileextension \
+ repositorycategories \
startmenu \
systeminfo \
stylesheet
diff --git a/examples/repositorycategories/README b/examples/repositorycategories/README
new file mode 100644
index 000000000..4a1f491c6
--- /dev/null
+++ b/examples/repositorycategories/README
@@ -0,0 +1,30 @@
+Shows how to set up an online installer and how to use categorized repositories. Categorized repositories are not loaded to the tree view by default, instead you can select
+to show categorized repositories in a tree view combobox. By default, repositories without categories are always shown in the tree view.
+
+The example uses a very simple web server shipped with Python.
+
+Generate the online repositories with
+
+ repogen -p packages repository
+ repogen -p packages_forcategory1 repository1
+ repogen -p packages2_forcategory1 repository2
+ repogen -p packages_forcategory2 repository3
+
+Generate the installer with
+
+ binarycreator --online-only -c config/config.xml -p packages installer
+
+Now launch a minimal web server in the example's directory (admin rights may be needed)
+
+ python -m SimpleHTTPServer 80
+
+This should make the content of the local directory available under
+http://localhost
+
+You should be able to now launch the installer.
+
+To deploy an update, run
+
+ repogen --update-new-components -p packages_update repository
+
+and launch the maintenance tool in your installation.
diff --git a/examples/repositorycategories/config/config.xml b/examples/repositorycategories/config/config.xml
new file mode 100644
index 000000000..c61e4893d
--- /dev/null
+++ b/examples/repositorycategories/config/config.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Installer>
+ <Name>Repository category Installer Example</Name>
+ <Version>1.0.0</Version>
+ <Title>Repository category Installer Example</Title>
+ <Publisher>The Qt Company</Publisher>
+ <!-- Directory name is used in component.xml -->
+ <StartMenuDir>Qt IFW Examples</StartMenuDir>
+ <TargetDir>@HomeDir@/IfwExamples/repositoryCategories</TargetDir>
+ <RemoteRepositories>
+ <Repository>
+ <Url>http://localhost/repository</Url>
+ </Repository>
+ </RemoteRepositories>
+ <RepositoryCategories>
+ <RepositoryCategoryDisplayname>Releases</RepositoryCategoryDisplayname>
+ <RemoteRepositories>
+ <DisplayName>Category 1</DisplayName>
+ <Repository>
+ <Url>http://localhost/repository1</Url>
+ </Repository>
+ <Repository>
+ <Url>http://localhost/repository2</Url>
+ </Repository>
+ </RemoteRepositories>
+ <RemoteRepositories>
+ <DisplayName>Category 2</DisplayName>
+ <Repository>
+ <Url>http://localhost/repository3</Url>
+ </Repository>
+ </RemoteRepositories>
+ </RepositoryCategories>
+</Installer>
diff --git a/examples/repositorycategories/packages/A/data/A.txt b/examples/repositorycategories/packages/A/data/A.txt
new file mode 100644
index 000000000..98114dd6e
--- /dev/null
+++ b/examples/repositorycategories/packages/A/data/A.txt
@@ -0,0 +1,2 @@
+Example content for package A.
+
diff --git a/examples/repositorycategories/packages/A/meta/package.xml b/examples/repositorycategories/packages/A/meta/package.xml
new file mode 100644
index 000000000..08cef59c0
--- /dev/null
+++ b/examples/repositorycategories/packages/A/meta/package.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Package>
+ <DisplayName>A</DisplayName>
+ <Description>Example component A</Description>
+ <Version>1.0.2-1</Version>
+ <ReleaseDate>2015-01-01</ReleaseDate>
+ <Default>true</Default>
+</Package>
diff --git a/examples/repositorycategories/packages/B/data/B.txt b/examples/repositorycategories/packages/B/data/B.txt
new file mode 100644
index 000000000..1ee864074
--- /dev/null
+++ b/examples/repositorycategories/packages/B/data/B.txt
@@ -0,0 +1,2 @@
+Example content for package B.
+
diff --git a/examples/repositorycategories/packages/B/meta/package.xml b/examples/repositorycategories/packages/B/meta/package.xml
new file mode 100644
index 000000000..44e90b9a2
--- /dev/null
+++ b/examples/repositorycategories/packages/B/meta/package.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Package>
+ <DisplayName>B</DisplayName>
+ <Description>Example component B</Description>
+ <Version>1.0.0-1</Version>
+ <ReleaseDate>2015-01-01</ReleaseDate>
+ <Default>true</Default>
+</Package>
diff --git a/examples/repositorycategories/packages2_forcategory1/A2Cagetory1/data/A2_category1.txt b/examples/repositorycategories/packages2_forcategory1/A2Cagetory1/data/A2_category1.txt
new file mode 100644
index 000000000..2b328a750
--- /dev/null
+++ b/examples/repositorycategories/packages2_forcategory1/A2Cagetory1/data/A2_category1.txt
@@ -0,0 +1,2 @@
+Example content for package A2, using category 1.
+
diff --git a/examples/repositorycategories/packages2_forcategory1/A2Cagetory1/meta/package.xml b/examples/repositorycategories/packages2_forcategory1/A2Cagetory1/meta/package.xml
new file mode 100644
index 000000000..02d175868
--- /dev/null
+++ b/examples/repositorycategories/packages2_forcategory1/A2Cagetory1/meta/package.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Package>
+ <DisplayName>A2 (from category 1)</DisplayName>
+ <Description>Example component A2</Description>
+ <Version>1.0.3-1</Version>
+ <ReleaseDate>2015-01-01</ReleaseDate>
+ <Default>true</Default>
+</Package>
diff --git a/examples/repositorycategories/packages2_forcategory1/B2Category1/data/B2_category1.txt b/examples/repositorycategories/packages2_forcategory1/B2Category1/data/B2_category1.txt
new file mode 100644
index 000000000..56baa1709
--- /dev/null
+++ b/examples/repositorycategories/packages2_forcategory1/B2Category1/data/B2_category1.txt
@@ -0,0 +1,2 @@
+Example content for package B2, using category 1.
+
diff --git a/examples/repositorycategories/packages2_forcategory1/B2Category1/meta/package.xml b/examples/repositorycategories/packages2_forcategory1/B2Category1/meta/package.xml
new file mode 100644
index 000000000..0c0b0411d
--- /dev/null
+++ b/examples/repositorycategories/packages2_forcategory1/B2Category1/meta/package.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Package>
+ <DisplayName>B2 (from category 1)</DisplayName>
+ <Description>Example component B</Description>
+ <Version>1.0.0-1</Version>
+ <ReleaseDate>2015-01-01</ReleaseDate>
+ <Default>true</Default>
+</Package>
diff --git a/examples/repositorycategories/packages_forcategory1/ACagetory1/data/A_category1.txt b/examples/repositorycategories/packages_forcategory1/ACagetory1/data/A_category1.txt
new file mode 100644
index 000000000..e899cb202
--- /dev/null
+++ b/examples/repositorycategories/packages_forcategory1/ACagetory1/data/A_category1.txt
@@ -0,0 +1,2 @@
+Example content for package A, using category 1.
+
diff --git a/examples/repositorycategories/packages_forcategory1/ACagetory1/meta/package.xml b/examples/repositorycategories/packages_forcategory1/ACagetory1/meta/package.xml
new file mode 100644
index 000000000..1f0e795e9
--- /dev/null
+++ b/examples/repositorycategories/packages_forcategory1/ACagetory1/meta/package.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Package>
+ <DisplayName>A (from category 1)</DisplayName>
+ <Description>Example component A</Description>
+ <Version>1.0.3-1</Version>
+ <ReleaseDate>2015-01-01</ReleaseDate>
+ <Default>true</Default>
+</Package>
diff --git a/examples/repositorycategories/packages_forcategory1/BCategory1/data/B_category1.txt b/examples/repositorycategories/packages_forcategory1/BCategory1/data/B_category1.txt
new file mode 100644
index 000000000..d355cb633
--- /dev/null
+++ b/examples/repositorycategories/packages_forcategory1/BCategory1/data/B_category1.txt
@@ -0,0 +1,2 @@
+Example content for package B, using category 1.
+
diff --git a/examples/repositorycategories/packages_forcategory1/BCategory1/meta/package.xml b/examples/repositorycategories/packages_forcategory1/BCategory1/meta/package.xml
new file mode 100644
index 000000000..98b9776fd
--- /dev/null
+++ b/examples/repositorycategories/packages_forcategory1/BCategory1/meta/package.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Package>
+ <DisplayName>B (from category 1)</DisplayName>
+ <Description>Example component B</Description>
+ <Version>1.0.0-1</Version>
+ <ReleaseDate>2015-01-01</ReleaseDate>
+ <Default>true</Default>
+</Package>
diff --git a/examples/repositorycategories/packages_forcategory2/ACategory2/data/A_category2.txt b/examples/repositorycategories/packages_forcategory2/ACategory2/data/A_category2.txt
new file mode 100644
index 000000000..0a10aa452
--- /dev/null
+++ b/examples/repositorycategories/packages_forcategory2/ACategory2/data/A_category2.txt
@@ -0,0 +1,2 @@
+Example content for package A, using category 2.
+
diff --git a/examples/repositorycategories/packages_forcategory2/ACategory2/meta/package.xml b/examples/repositorycategories/packages_forcategory2/ACategory2/meta/package.xml
new file mode 100644
index 000000000..25a25f94e
--- /dev/null
+++ b/examples/repositorycategories/packages_forcategory2/ACategory2/meta/package.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Package>
+ <DisplayName>A (from category 2)</DisplayName>
+ <Description>Example component A</Description>
+ <Version>1.0.3-1</Version>
+ <ReleaseDate>2015-01-01</ReleaseDate>
+ <Default>true</Default>
+</Package>
diff --git a/examples/repositorycategories/packages_forcategory2/BCategory2/data/B_category2.txt b/examples/repositorycategories/packages_forcategory2/BCategory2/data/B_category2.txt
new file mode 100644
index 000000000..ebf02b452
--- /dev/null
+++ b/examples/repositorycategories/packages_forcategory2/BCategory2/data/B_category2.txt
@@ -0,0 +1,2 @@
+Example content for package B, using category 2.
+
diff --git a/examples/repositorycategories/packages_forcategory2/BCategory2/meta/package.xml b/examples/repositorycategories/packages_forcategory2/BCategory2/meta/package.xml
new file mode 100644
index 000000000..fa21c631b
--- /dev/null
+++ b/examples/repositorycategories/packages_forcategory2/BCategory2/meta/package.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Package>
+ <DisplayName>B (from category 2)</DisplayName>
+ <Description>Example component B</Description>
+ <Version>1.0.0-1</Version>
+ <ReleaseDate>2015-01-01</ReleaseDate>
+ <Default>true</Default>
+</Package>
diff --git a/examples/repositorycategories/repositorycategories.pro b/examples/repositorycategories/repositorycategories.pro
new file mode 100644
index 000000000..37a0144b7
--- /dev/null
+++ b/examples/repositorycategories/repositorycategories.pro
@@ -0,0 +1,13 @@
+TEMPLATE = aux
+
+INSTALLER = installer
+
+INPUT = $$PWD/config/config.xml $$PWD/packages
+example.input = INPUT
+example.output = $$INSTALLER
+example.commands = ../../bin/binarycreator --online-only -c $$PWD/config/config.xml -p $$PWD/packages ${QMAKE_FILE_OUT}
+example.CONFIG += target_predeps no_link combine
+
+QMAKE_EXTRA_COMPILERS += example
+
+OTHER_FILES = README
diff --git a/src/libs/installer/constants.h b/src/libs/installer/constants.h
index 0e9646737..26c2a7dfe 100644
--- a/src/libs/installer/constants.h
+++ b/src/libs/installer/constants.h
@@ -91,6 +91,7 @@ static const QLatin1String scAllUsers("AllUsers");
static const QLatin1String scSupportsModify("SupportsModify");
static const QLatin1String scAllowUnstableComponents("AllowUnstableComponents");
static const QLatin1String scSaveDefaultRepositories("SaveDefaultRepositories");
+static const QLatin1String scRepositoryCategoryDisplayName("RepositoryCategoryDisplayName");
const char scRelocatable[] = "@RELOCATABLE_PATH@";
diff --git a/src/libs/installer/installer.pro b/src/libs/installer/installer.pro
index f649a1ecb..bdca7e0f3 100644
--- a/src/libs/installer/installer.pro
+++ b/src/libs/installer/installer.pro
@@ -131,7 +131,8 @@ HEADERS += packagemanagercore.h \
lib7z_guid.h \
lib7z_create.h \
lib7z_extract.h \
- lib7z_list.h
+ lib7z_list.h \
+ repositorycategory.h
SOURCES += packagemanagercore.cpp \
packagemanagercore_p.cpp \
@@ -206,7 +207,8 @@ SOURCES += packagemanagercore.cpp \
serverauthenticationdialog.cpp \
keepaliveobject.cpp \
systeminfo.cpp \
- packagesource.cpp
+ packagesource.cpp \
+ repositorycategory.cpp
FORMS += proxycredentialsdialog.ui \
serverauthenticationdialog.ui
diff --git a/src/libs/installer/metadatajob.cpp b/src/libs/installer/metadatajob.cpp
index ae29a2dcb..cb1579756 100644
--- a/src/libs/installer/metadatajob.cpp
+++ b/src/libs/installer/metadatajob.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -70,11 +70,33 @@ MetadataJob::~MetadataJob()
reset();
}
-Repository MetadataJob::repositoryForDirectory(const QString &directory) const
+/*
+ * Parse the metadata of currently selected repositories. We cannot
+ * return all metadata as that contains metadata also from categorized archived
+ * repositories which might not be currently selected.
+ */
+
+QList<Metadata> MetadataJob::metadata() const
{
- return m_metadata.value(directory).repository;
+ QList<Metadata> metadata = m_metaFromDefaultRepositories.values();
+ foreach (RepositoryCategory repositoryCategory, m_core->settings().repositoryCategories()) {
+ if (m_core->isUpdater() || (repositoryCategory.isEnabled() && m_fetchedArchive.contains(repositoryCategory.displayname()))) {
+ QList<ArchiveMetadata> archiveMetaList = m_fetchedArchive.values(repositoryCategory.displayname());
+ foreach (ArchiveMetadata archiveMeta, archiveMetaList) {
+ metadata.append(archiveMeta.metaData);
+ }
+ }
+ }
+ return metadata;
}
+Repository MetadataJob::repositoryForDirectory(const QString &directory) const
+{
+ if (m_metaFromDefaultRepositories.contains(directory))
+ return m_metaFromDefaultRepositories.value(directory).repository;
+ else
+ return m_metaFromArchive.value(directory).repository;
+}
// -- private slots
@@ -86,13 +108,12 @@ void MetadataJob::doStart()
}
const ProductKeyCheck *const productKeyCheck = ProductKeyCheck::instance();
if (!m_addCompressedPackages) {
- reset();
emit infoMessage(this, tr("Preparing meta information download..."));
const bool onlineInstaller = m_core->isInstaller() && !m_core->isOfflineOnly();
-
if (onlineInstaller || m_core->isMaintainer()) {
QList<FileTaskItem> items;
- foreach (const Repository &repo, m_core->settings().repositories()) {
+ QSet<Repository> repositories = getRepositories();
+ foreach (const Repository &repo, repositories) {
if (repo.isEnabled() &&
productKeyCheck->isValidRepository(repo)) {
QAuthenticator authenticator;
@@ -451,7 +472,9 @@ bool MetadataJob::fetchMetaDataPackages()
void MetadataJob::reset()
{
m_packages.clear();
- m_metadata.clear();
+ m_metaFromDefaultRepositories.clear();
+ m_metaFromArchive.clear();
+ m_fetchedArchive.clear();
setError(Job::NoError);
setErrorString(QString());
@@ -587,7 +610,17 @@ MetadataJob::Status MetadataJob::parseUpdatesXml(const QList<FileTaskResult> &re
}
}
}
- m_metadata.insert(metadata.directory, metadata);
+ if (metadata.repository.archivename().isEmpty()) {
+ m_metaFromDefaultRepositories.insert(metadata.directory, metadata);
+ } else {
+ //Hash metadata to help checking if meta for repository is already fetched
+ ArchiveMetadata archiveMetadata;
+ archiveMetadata.metaData = metadata;
+ m_fetchedArchive.insertMulti(metadata.repository.archivename(), archiveMetadata);
+ // Hash for faster lookups
+ m_metaFromArchive.insert(metadata.directory, metadata);
+ }
+
// search for additional repositories that we might need to check
const QDomNode repositoryUpdate = root.firstChildElement(QLatin1String("RepositoryUpdate"));
@@ -670,8 +703,31 @@ MetadataJob::Status MetadataJob::parseUpdatesXml(const QList<FileTaskResult> &re
}
double taskCount = m_packages.length()/static_cast<double>(m_downloadableChunkSize);
m_totalTaskCount = qCeil(taskCount);
+ m_taskNumber = 0;
return XmlDownloadSuccess;
}
+QSet<Repository> MetadataJob::getRepositories()
+{
+ QSet<Repository> repositories;
+
+ //In the first run, m_metadata is empty. Get always the default repositories
+ if (m_metaFromDefaultRepositories.isEmpty()) {
+ repositories = m_core->settings().repositories();
+ }
+
+ // Fetch repositories under archive which are selected in UI.
+ // If repository is already fetched, do not fetch it again.
+ // In updater mode, fetch always all archive repositories to get updates
+ foreach (RepositoryCategory repositoryCategory, m_core->settings().repositoryCategories()) {
+ if (m_core->isUpdater() || (repositoryCategory.isEnabled() && !m_fetchedArchive.contains(repositoryCategory.displayname()))) {
+ foreach (Repository repository, repositoryCategory.repositories()) {
+ repositories.insert(repository);
+ }
+ }
+ }
+ return repositories;
+}
+
} // namespace QInstaller
diff --git a/src/libs/installer/metadatajob.h b/src/libs/installer/metadatajob.h
index e3f5aceea..973275de3 100644
--- a/src/libs/installer/metadatajob.h
+++ b/src/libs/installer/metadatajob.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -46,6 +46,12 @@ struct Metadata
Repository repository;
};
+struct ArchiveMetadata
+{
+ QString archive;
+ Metadata metaData;
+};
+
class INSTALLER_EXPORT MetadataJob : public Job
{
Q_OBJECT
@@ -61,7 +67,7 @@ public:
explicit MetadataJob(QObject *parent = 0);
~MetadataJob();
- QList<Metadata> metadata() const { return m_metadata.values(); }
+ QList<Metadata> metadata() const;
Repository repositoryForDirectory(const QString &directory) const;
void setPackageManagerCore(PackageManagerCore *core) { m_core = core; }
void addCompressedPackages(bool addCompressPackage) { m_addCompressedPackages = addCompressPackage;}
@@ -85,13 +91,13 @@ private:
void reset();
void resetCompressedFetch();
Status parseUpdatesXml(const QList<FileTaskResult> &results);
+ QSet<Repository> getRepositories();
private:
PackageManagerCore *m_core;
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;
@@ -103,6 +109,9 @@ private:
int m_taskNumber;
int m_totalTaskCount;
QStringList m_shaMissmatchPackages;
+ QHash<QString, ArchiveMetadata> m_fetchedArchive;
+ QHash<QString, Metadata> m_metaFromDefaultRepositories;
+ QHash<QString, Metadata> m_metaFromArchive; //for faster lookups.
};
} // namespace QInstaller
diff --git a/src/libs/installer/packagemanagercore.cpp b/src/libs/installer/packagemanagercore.cpp
index 747960cee..44025de55 100644
--- a/src/libs/installer/packagemanagercore.cpp
+++ b/src/libs/installer/packagemanagercore.cpp
@@ -1176,7 +1176,6 @@ bool PackageManagerCore::fetchCompressedPackagesTree()
return fetchPackagesTree(packages, installedPackages);
}
-
/*!
Checks for packages to install. Returns \c true if newer versions exist
and they can be installed.
diff --git a/src/libs/installer/packagemanagercore_p.cpp b/src/libs/installer/packagemanagercore_p.cpp
index 195c16f30..1e271a0d5 100644
--- a/src/libs/installer/packagemanagercore_p.cpp
+++ b/src/libs/installer/packagemanagercore_p.cpp
@@ -2210,14 +2210,12 @@ LocalPackagesHash PackageManagerCorePrivate::localInstalledPackages()
bool PackageManagerCorePrivate::fetchMetaInformationFromRepositories()
{
- if (m_repoFetched)
- return m_repoFetched;
-
m_updates = false;
m_repoFetched = false;
m_updateSourcesAdded = false;
try {
+ m_metadataJob.addCompressedPackages(false);
m_metadataJob.start();
m_metadataJob.waitForFinished();
} catch (Error &error) {
diff --git a/src/libs/installer/packagemanagergui.cpp b/src/libs/installer/packagemanagergui.cpp
index 287bf7d38..90ff11ea3 100644
--- a/src/libs/installer/packagemanagergui.cpp
+++ b/src/libs/installer/packagemanagergui.cpp
@@ -39,6 +39,7 @@
#include "utils.h"
#include "scriptengine.h"
#include "productkeycheck.h"
+#include "repositorycategory.h"
#include "sysinfo.h"
@@ -71,6 +72,7 @@
#include <QVBoxLayout>
#include <QShowEvent>
#include <QFileDialog>
+#include <QGroupBox>
#ifdef Q_OS_WIN
# include <qt_windows.h>
@@ -1863,6 +1865,8 @@ public:
, m_updaterModel(m_core->updaterComponentModel())
, m_currentModel(m_allModel)
, m_compressedButtonVisible(false)
+ , m_allowCompressedRepositoryInstall(false)
+ , m_archiveButtonVisible(false)
{
m_treeView->setObjectName(QLatin1String("ComponentsTreeView"));
@@ -1871,32 +1875,42 @@ public:
connect(m_updaterModel, SIGNAL(checkStateChanged(QInstaller::ComponentModel::ModelState)),
this, SLOT(onModelStateChanged(QInstaller::ComponentModel::ModelState)));
- QHBoxLayout *hlayout = new QHBoxLayout;
- hlayout->addWidget(m_treeView, 3);
+ m_descriptionVLayout = new QVBoxLayout;
+ m_descriptionVLayout->setObjectName(QLatin1String("DescriptionLayout"));
m_descriptionLabel = new QLabel(q);
m_descriptionLabel->setWordWrap(true);
m_descriptionLabel->setObjectName(QLatin1String("ComponentDescriptionLabel"));
-
- m_vlayout = new QVBoxLayout;
- m_vlayout->setObjectName(QLatin1String("VerticalLayout"));
- m_vlayout->addWidget(m_descriptionLabel);
+ m_descriptionVLayout->addWidget(m_descriptionLabel);
m_sizeLabel = new QLabel(q);
m_sizeLabel->setWordWrap(true);
- m_vlayout->addWidget(m_sizeLabel);
m_sizeLabel->setObjectName(QLatin1String("ComponentSizeLabel"));
-
-#ifdef INSTALLCOMPRESSED
- allowCompressedRepositoryInstall();
-#endif
- m_vlayout->addSpacerItem(new QSpacerItem(1, 1, QSizePolicy::MinimumExpanding,
+ m_descriptionVLayout->addWidget(m_sizeLabel);
+ m_descriptionVLayout->addSpacerItem(new QSpacerItem(1, 1, QSizePolicy::MinimumExpanding,
QSizePolicy::MinimumExpanding));
- hlayout->addLayout(m_vlayout, 2);
- QVBoxLayout *layout = new QVBoxLayout(q);
- layout->addLayout(hlayout, 1);
+ m_mainHLayout = new QHBoxLayout;
+
+ m_treeViewVLayout = new QVBoxLayout;
+ m_treeViewVLayout->setObjectName(QLatin1String("TreeviewLayout"));
+
+ m_bspLabel = new QLabel();
+ m_bspLabel->hide();
+ m_treeViewVLayout->addWidget(m_bspLabel);
+
+ m_progressBar = new QProgressBar();
+ m_progressBar->setRange(0, 0);
+ m_progressBar->hide();
+ m_progressBar->setObjectName(QLatin1String("CompressedInstallProgressBar"));
+ m_treeViewVLayout->addWidget(m_progressBar);
+ connect(m_core, SIGNAL(metaJobProgress(int)), this, SLOT(onProgressChanged(int)));
+ connect(m_core, SIGNAL(metaJobInfoMessage(QString)), this, SLOT(setMessage(QString)));
+ connect(m_core, &PackageManagerCore::metaJobTotalProgress, this,
+ &ComponentSelectionPage::Private::setTotalProgress);
+
+ m_buttonHLayout = new QHBoxLayout;
m_checkDefault = new QPushButton;
connect(m_checkDefault, &QAbstractButton::clicked,
this, &ComponentSelectionPage::Private::selectDefault);
@@ -1912,62 +1926,93 @@ public:
"reset to already installed components")));
m_checkDefault->setText(ComponentSelectionPage::tr("&Reset"));
}
- hlayout = new QHBoxLayout;
- hlayout->addWidget(m_checkDefault);
+ m_buttonHLayout->addWidget(m_checkDefault);
m_checkAll = new QPushButton;
- hlayout->addWidget(m_checkAll);
connect(m_checkAll, &QAbstractButton::clicked,
this, &ComponentSelectionPage::Private::selectAll);
m_checkAll->setObjectName(QLatin1String("SelectAllComponentsButton"));
m_checkAll->setShortcut(QKeySequence(ComponentSelectionPage::tr("Alt+S",
"select all components")));
m_checkAll->setText(ComponentSelectionPage::tr("&Select All"));
+ m_buttonHLayout->addWidget(m_checkAll);
m_uncheckAll = new QPushButton;
- hlayout->addWidget(m_uncheckAll);
connect(m_uncheckAll, &QAbstractButton::clicked,
this, &ComponentSelectionPage::Private::deselectAll);
m_uncheckAll->setObjectName(QLatin1String("DeselectAllComponentsButton"));
m_uncheckAll->setShortcut(QKeySequence(ComponentSelectionPage::tr("Alt+D",
"deselect all components")));
m_uncheckAll->setText(ComponentSelectionPage::tr("&Deselect All"));
+ m_buttonHLayout->addWidget(m_uncheckAll);
- hlayout->addSpacerItem(new QSpacerItem(1, 1, QSizePolicy::MinimumExpanding,
- QSizePolicy::MinimumExpanding));
- layout->addLayout(hlayout);
+ m_treeViewVLayout->addLayout(m_buttonHLayout);
+ m_treeViewVLayout->addWidget(m_treeView, 3);
+
+ m_mainHLayout->addLayout(m_treeViewVLayout, 3);
+ m_mainHLayout->addLayout(m_descriptionVLayout, 2);
+ QVBoxLayout *layout = new QVBoxLayout(q);
+ layout->addLayout(m_mainHLayout, 1);
+
+#ifdef INSTALLCOMPRESSED
+ allowCompressedRepositoryInstall();
+#endif
}
void allowCompressedRepositoryInstall()
{
- if (m_compressedButtonVisible) {
+ m_allowCompressedRepositoryInstall = true;
+ }
+
+ void showCompressedRepositoryButton()
+ {
+ if (m_compressedButtonVisible || !m_allowCompressedRepositoryInstall) {
return;
}
-
connect(m_core, SIGNAL(metaJobProgress(int)), this, SLOT(onProgressChanged(int)));
connect(m_core, SIGNAL(metaJobInfoMessage(QString)), this, SLOT(setMessage(QString)));
- m_bspLabel = new QLabel(ComponentSelectionPage::tr("To install new "\
- "compressed repository, browse the repositories from your computer"),q);
- m_bspLabel->setWordWrap(true);
- m_bspLabel->setObjectName(QLatin1String("CompressedButtonLabel"));
-
- m_vlayout->addSpacing(50);
- m_vlayout->addWidget(m_bspLabel);
+ QWizard *wizard = qobject_cast<QWizard*>(m_core->guiObject());
+ if (wizard) {
+ wizard->setOption(QWizard::HaveCustomButton2, true);
+ wizard->setButtonText(QWizard::CustomButton2,
+ ComponentSelectionPage::tr("&Browse QBSP files"));
+ connect(wizard, &QWizard::customButtonClicked,
+ this, &ComponentSelectionPage::Private::selectCompressedPackage);
+ q->gui()->updateButtonLayout();
+ }
+ m_compressedButtonVisible = true;
+ }
- m_progressBar = new QProgressBar();
- m_progressBar->setRange(0, 0);
- m_progressBar->hide();
- m_vlayout->addWidget(m_progressBar);
- m_progressBar->setObjectName(QLatin1String("CompressedInstallProgressBar"));
+ void setupArchiveButton()
+ {
+ if (m_archiveButtonVisible)
+ return;
+ QVBoxLayout *vLayout = new QVBoxLayout;
+ m_archiveVLayout = new QVBoxLayout;
+ m_archiveGroupBox = new QGroupBox(q);
+ m_archiveGroupBox->setTitle(m_core->settings().repositoryCategoryDisplayName());
+ QVBoxLayout *groupboxLayout = new QVBoxLayout(m_archiveGroupBox);
+
+ m_fetchArchiveButton = new QPushButton(tr("Fetch"));
+ connect(m_fetchArchiveButton, &QPushButton::clicked, this,
+ &ComponentSelectionPage::Private::fetchRepositoryCategories);
+ foreach (RepositoryCategory repository, m_core->settings().repositoryCategories()) {
+ QCheckBox *checkBox = new QCheckBox;
+ connect(checkBox, &QCheckBox::stateChanged, this,
+ &ComponentSelectionPage::Private::checkboxStateChanged);
+ checkBox->setText(repository.displayname());
+ groupboxLayout->addWidget(checkBox);
+ }
+ m_archiveVLayout->insertWidget(0, m_archiveGroupBox);
- m_installCompressButton = new QPushButton;
- connect(m_installCompressButton, &QAbstractButton::clicked,
- this, &ComponentSelectionPage::Private::selectCompressedPackage);
- m_installCompressButton->setObjectName(QLatin1String("InstallCompressedPackageButton"));
- m_installCompressButton->setText(ComponentSelectionPage::tr("&Browse QBSP files"));
- m_vlayout->addWidget(m_installCompressButton);
- m_compressedButtonVisible = true;
+ m_metadataProgressLabel = new QLabel(q);
+ m_archiveVLayout->addWidget(m_metadataProgressLabel);
+ vLayout->addWidget(m_archiveGroupBox);
+ vLayout->addWidget(m_fetchArchiveButton);
+ vLayout->addStretch();
+ m_mainHLayout->insertLayout(0, vLayout);
+ m_archiveButtonVisible = true;
}
void updateTreeView()
@@ -2061,6 +2106,77 @@ public slots:
m_currentModel->setCheckedState(ComponentModel::AllUnchecked);
}
+ void checkboxStateChanged()
+ {
+ QList<QCheckBox*> checkboxes = m_archiveGroupBox->findChildren<QCheckBox *>();
+ bool enableFetchButton = false;
+ foreach (QCheckBox *checkbox, checkboxes) {
+ if (checkbox->isChecked()) {
+ enableFetchButton = true;
+ break;
+ }
+ }
+ }
+
+ void enableArchiveRepos(int index, bool enable) {
+ RepositoryCategory archiveRepo = m_core->settings().repositoryCategories().toList().at(index);
+ RepositoryCategory replacement = archiveRepo;
+ replacement.setEnabled(enable);
+ QSet<RepositoryCategory> tmpArchiveRepos = m_core->settings().repositoryCategories();
+ if (tmpArchiveRepos.contains(archiveRepo)) {
+ tmpArchiveRepos.remove(archiveRepo);
+ tmpArchiveRepos.insert(replacement);
+ m_core->settings().addRepositoryCategories(tmpArchiveRepos);
+ }
+ }
+
+ void updateWidgetVisibility(bool show)
+ {
+ if (show) {
+ QSpacerItem *verticalSpacer2 = new QSpacerItem(0, 0, QSizePolicy::Minimum,
+ QSizePolicy::Expanding);
+ m_treeViewVLayout->addSpacerItem(verticalSpacer2);
+ } else {
+ QSpacerItem *item = m_treeViewVLayout->spacerItem();
+ m_treeViewVLayout->removeItem(item);
+ }
+ m_fetchArchiveButton->setDisabled(show);
+ m_progressBar->setVisible(show);
+ m_bspLabel->setVisible(show);
+ m_archiveGroupBox->setDisabled(show);
+
+ m_treeView->setVisible(!show);
+ m_checkDefault->setVisible(!show);
+ m_checkAll->setVisible(!show);
+ m_uncheckAll->setVisible(!show);
+ m_descriptionLabel->setVisible(!show);
+ QPushButton *const b = qobject_cast<QPushButton *>(q->gui()->button(QWizard::NextButton));
+ b->setEnabled(!show);
+
+ if (QAbstractButton *bspButton = q->gui()->button(QWizard::CustomButton2))
+ bspButton->setEnabled(!show);
+ }
+
+ void fetchRepositoryCategories()
+ {
+ updateWidgetVisibility(true);
+
+ QCheckBox *checkbox;
+ QList<QCheckBox*> checkboxes = m_archiveGroupBox->findChildren<QCheckBox *>();
+ for (int i = 0; i < checkboxes.count(); i++) {
+ checkbox = checkboxes.at(i);
+ enableArchiveRepos(i, checkbox->isChecked());
+ }
+
+ if (!m_core->fetchRemotePackagesTree()) {
+ m_metadataProgressLabel->setText(m_core->error());
+ } else {
+ updateTreeView();
+ m_metadataProgressLabel->setText(QLatin1String());
+ }
+ updateWidgetVisibility(false);
+ }
+
void selectCompressedPackage()
{
QString defaultDownloadDirectory =
@@ -2076,10 +2192,7 @@ public slots:
set.insert(repository);
}
if (set.count() > 0) {
- m_progressBar->show();
- m_installCompressButton->hide();
- QPushButton *const b = qobject_cast<QPushButton *>(q->gui()->button(QWizard::NextButton));
- b->setEnabled(false);
+ updateWidgetVisibility(true);
m_core->settings().addTemporaryRepositories(set, false);
if (!m_core->fetchCompressedPackagesTree()) {
setMessage(m_core->error());
@@ -2089,11 +2202,8 @@ public slots:
setMessage(ComponentSelectionPage::tr("To install new "\
"compressed repository, browse the repositories from your computer"));
}
-
- m_progressBar->hide();
- m_installCompressButton->show();
- b->setEnabled(true);
}
+ updateWidgetVisibility(false);
}
/*!
@@ -2114,6 +2224,12 @@ public slots:
m_bspLabel->setText(msg);
}
+ void setTotalProgress(int totalProgress)
+ {
+ if (m_progressBar)
+ m_progressBar->setRange(0, totalProgress);
+ }
+
void selectDefault()
{
m_currentModel->setCheckedState(ComponentModel::DefaultChecked);
@@ -2152,10 +2268,19 @@ public:
QPushButton *m_uncheckAll;
QPushButton *m_checkDefault;
QPushButton *m_installCompressButton;
+ QGroupBox *m_archiveGroupBox;
+ QPushButton *m_fetchArchiveButton;
QLabel *m_bspLabel;
+ QLabel *m_metadataProgressLabel;
QProgressBar *m_progressBar;
- QVBoxLayout *m_vlayout;
+ QVBoxLayout *m_descriptionVLayout;
+ QHBoxLayout *m_mainHLayout;
+ QVBoxLayout *m_treeViewVLayout;
+ QVBoxLayout *m_archiveVLayout;
+ QHBoxLayout *m_buttonHLayout;
bool m_compressedButtonVisible;
+ bool m_allowCompressedRepositoryInstall;
+ bool m_archiveButtonVisible;
};
@@ -2211,6 +2336,21 @@ void ComponentSelectionPage::entering()
d->updateTreeView();
setModified(isComplete());
+ if (core->settings().repositoryCategories().count() > 0 && !core->isOfflineOnly()
+ && !core->isUpdater()) {
+ d->setupArchiveButton();
+ }
+ d->showCompressedRepositoryButton();
+}
+
+void ComponentSelectionPage::leaving()
+{
+ QWizard *wizard = qobject_cast<QWizard*>(d->m_core->guiObject());
+ if (wizard && (gui()->options() & QWizard::HaveCustomButton2)) {
+ wizard->setOption(QWizard::HaveCustomButton2, false);
+ gui()->updateButtonLayout();
+ d->m_compressedButtonVisible = false;
+ }
}
/*!
diff --git a/src/libs/installer/packagemanagergui.h b/src/libs/installer/packagemanagergui.h
index 238e22a62..d67bc9bd9 100644
--- a/src/libs/installer/packagemanagergui.h
+++ b/src/libs/installer/packagemanagergui.h
@@ -314,6 +314,7 @@ public:
protected:
void entering();
+ void leaving();
void showEvent(QShowEvent *event);
private Q_SLOTS:
diff --git a/src/libs/installer/repository.cpp b/src/libs/installer/repository.cpp
index eb45573a9..249012786 100644
--- a/src/libs/installer/repository.cpp
+++ b/src/libs/installer/repository.cpp
@@ -57,6 +57,7 @@ Repository::Repository(const Repository &other)
, m_password(other.m_password)
, m_displayname(other.m_displayname)
, m_compressed(other.m_compressed)
+ , m_archivename(other.m_archivename)
{
registerMetaType();
}
@@ -183,7 +184,7 @@ void Repository::setPassword(const QString &password)
}
/*!
- Returns the Name for the repository to be displayed instead of the URL
+ Returns the Name for the repository to be displayed instead of the URL.
*/
QString Repository::displayname() const
{
@@ -199,6 +200,22 @@ void Repository::setDisplayName(const QString &displayname)
}
/*!
+ Returns the archive name if the repository belongs to an archive.
+*/
+QString Repository::archivename() const
+{
+ return m_archivename;
+}
+
+/*!
+ Sets the archive name to \a archivename if the repository belongs to an archive.
+*/
+void Repository::setArchiveName(const QString &archivename)
+{
+ m_archivename = archivename;
+}
+
+/*!
Returns true if repository is compressed
*/
bool Repository::isCompressed() const
@@ -248,6 +265,7 @@ const Repository &Repository::operator=(const Repository &other)
m_password = other.m_password;
m_displayname = other.m_displayname;
m_compressed = other.m_compressed;
+ m_archivename = other.m_archivename;
return *this;
}
@@ -273,7 +291,7 @@ QDataStream &operator<<(QDataStream &ostream, const Repository &repository)
{
return ostream << repository.m_url.toEncoded().toBase64() << repository.m_default << repository.m_enabled
<< repository.m_username.toUtf8().toBase64() << repository.m_password.toUtf8().toBase64()
- << repository.m_displayname.toUtf8().toBase64();
+ << repository.m_displayname.toUtf8().toBase64() << repository.m_archivename.toUtf8().toBase64();
}
}
diff --git a/src/libs/installer/repository.h b/src/libs/installer/repository.h
index b73e7bd4c..83393ead9 100644
--- a/src/libs/installer/repository.h
+++ b/src/libs/installer/repository.h
@@ -64,6 +64,9 @@ public:
QString displayname() const;
void setDisplayName(const QString &displayname);
+ QString archivename() const;
+ void setArchiveName(const QString &archivename);
+
bool isCompressed() const;
void setCompressed(bool compressed);
bool operator==(const Repository &other) const;
@@ -82,6 +85,7 @@ private:
QString m_username;
QString m_password;
QString m_displayname;
+ QString m_archivename;
bool m_compressed;
};
diff --git a/src/libs/installer/repositorycategory.cpp b/src/libs/installer/repositorycategory.cpp
new file mode 100644
index 000000000..af7f6e818
--- /dev/null
+++ b/src/libs/installer/repositorycategory.cpp
@@ -0,0 +1,159 @@
+/**************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+
+#include "repositorycategory.h"
+#include "filedownloaderfactory.h"
+
+#include <QDataStream>
+#include <QFileInfo>
+#include <QStringList>
+
+namespace QInstaller {
+
+
+template <typename T>
+static QSet<T> variantListToSet(const QVariantList &list)
+{
+ QSet<T> set;
+ foreach (const QVariant &variant, list)
+ set.insert(variant.value<T>());
+ return set;
+}
+
+/*!
+ Constructs an uninitialized RepositoryCategory object.
+*/
+RepositoryCategory::RepositoryCategory()
+ : m_enabled(false)
+{
+ registerMetaType();
+}
+
+/*!
+ Constructs a new category by using all fields of the given category \a other.
+*/
+RepositoryCategory::RepositoryCategory(const RepositoryCategory &other)
+ : m_displayname(other.m_displayname), m_data(other.m_data), m_enabled(other.m_enabled)
+{
+ registerMetaType();
+}
+
+
+void RepositoryCategory::registerMetaType()
+{
+ qRegisterMetaType<RepositoryCategory>("RepositoryCategory");
+ qRegisterMetaTypeStreamOperators<RepositoryCategory>("RepositoryCategory");
+}
+
+/*!
+ Returns the Name for the category to be displayed.
+*/
+QString RepositoryCategory::displayname() const
+{
+ return m_displayname;
+}
+
+/*!
+ Sets the DisplayName of the category to \a displayname.
+*/
+void RepositoryCategory::setDisplayName(const QString &displayname)
+{
+ m_displayname = displayname;
+}
+
+/*!
+ Returns the list of repositories the category has.
+*/
+QSet<Repository> RepositoryCategory::repositories() const
+{
+ return variantListToSet<Repository>(m_data.values(QLatin1String("Repositories")));
+}
+
+/*!
+ Inserts a set of \a repositories to the category.
+*/
+void RepositoryCategory::setRepositories(const QSet<Repository> repositories)
+{
+ foreach (const Repository &repository, repositories)
+ m_data.insertMulti(QLatin1String("Repositories"), QVariant().fromValue(repository));
+}
+
+/*!
+ Inserts \a repository to the category.
+*/
+void RepositoryCategory::addRepository(const Repository repository)
+{
+ m_data.insertMulti(QLatin1String("Repositories"), QVariant().fromValue(repository));
+}
+
+/*!
+ Returns whether this category is enabled and used during information retrieval.
+*/
+bool RepositoryCategory::isEnabled() const
+{
+ return m_enabled;
+}
+
+/*!
+ Sets this category to \a enabled state and and thus determines whether to use this
+ repository for information retrieval.
+
+*/
+void RepositoryCategory::setEnabled(bool enabled)
+{
+ m_enabled = enabled;
+}
+
+/*!
+ Compares the values of this category to \a other and returns true if they are equal.
+*/
+bool RepositoryCategory::operator==(const RepositoryCategory &other) const
+{
+ return m_displayname == other.m_displayname;
+}
+
+/*!
+ Returns true if the \a other category is not equal to this repository; otherwise returns false. Two
+ categories are considered equal if they contain the same displayname. \sa operator==()
+*/
+bool RepositoryCategory::operator!=(const RepositoryCategory &other) const
+{
+ return !(*this == other);
+}
+
+QDataStream &operator>>(QDataStream &istream, RepositoryCategory &repository)
+{
+ return istream;
+}
+
+QDataStream &operator<<(QDataStream &ostream, const RepositoryCategory &repository)
+{
+ return ostream << repository.m_displayname.toUtf8().toBase64() << repository.m_data;
+}
+
+}
diff --git a/src/libs/installer/repositorycategory.h b/src/libs/installer/repositorycategory.h
new file mode 100644
index 000000000..315af761b
--- /dev/null
+++ b/src/libs/installer/repositorycategory.h
@@ -0,0 +1,86 @@
+/**************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+
+#ifndef ARCHIVEREPOSITORY_H
+#define ARCHIVEREPOSITORY_H
+
+#include "installer_global.h"
+#include "repository.h"
+
+#include <QtCore/QMetaType>
+#include <QtCore/QUrl>
+#include <QSet>
+
+namespace QInstaller {
+
+class INSTALLER_EXPORT RepositoryCategory
+{
+
+public:
+ explicit RepositoryCategory();
+ RepositoryCategory(const RepositoryCategory &other);
+
+ static void registerMetaType();
+
+ QString displayname() const;
+ void setDisplayName(const QString &displayname);
+
+ QSet<Repository> repositories() const;
+ void setRepositories(const QSet<Repository> repositories);
+ void addRepository(const Repository repository);
+
+ bool isEnabled() const;
+ void setEnabled(bool enabled);
+
+ bool operator==(const RepositoryCategory &other) const;
+ bool operator!=(const RepositoryCategory &other) const;
+
+ uint qHash(const RepositoryCategory &repository);
+
+ friend INSTALLER_EXPORT QDataStream &operator>>(QDataStream &istream, RepositoryCategory &repository);
+ friend INSTALLER_EXPORT QDataStream &operator<<(QDataStream &ostream, const RepositoryCategory &repository);
+
+private:
+ QVariantHash m_data;
+ QString m_displayname;
+ bool m_enabled;
+};
+
+inline uint qHash(const RepositoryCategory &repository)
+{
+ return qHash(repository.displayname());
+}
+
+INSTALLER_EXPORT QDataStream &operator>>(QDataStream &istream, RepositoryCategory &repository);
+INSTALLER_EXPORT QDataStream &operator<<(QDataStream &ostream, const RepositoryCategory &repository);
+
+} // namespace QInstaller
+
+Q_DECLARE_METATYPE(QInstaller::RepositoryCategory)
+
+#endif // ARCHIVEREPOSITORY_H
diff --git a/src/libs/installer/settings.cpp b/src/libs/installer/settings.cpp
index 5761387c6..21bbe8b4c 100644
--- a/src/libs/installer/settings.cpp
+++ b/src/libs/installer/settings.cpp
@@ -30,6 +30,7 @@
#include "errors.h"
#include "qinstallerglobal.h"
#include "repository.h"
+#include "repositorycategory.h"
#include <QtCore/QFileInfo>
#include <QtCore/QStringList>
@@ -55,6 +56,7 @@ static const QLatin1String scUserRepositories("UserRepositories");
static const QLatin1String scTmpRepositories("TemporaryRepositories");
static const QLatin1String scMaintenanceToolIniFile("MaintenanceToolIniFile");
static const QLatin1String scRemoteRepositories("RemoteRepositories");
+static const QLatin1String scRepositoryCategories("RepositoryCategories");
static const QLatin1String scDependsOnLocalInstallerBinary("DependsOnLocalInstallerBinary");
static const QLatin1String scTranslations("Translations");
static const QLatin1String scCreateLocalRepository("CreateLocalRepository");
@@ -133,11 +135,15 @@ static QStringList readArgumentAttributes(QXmlStreamReader &reader, Settings::Pa
return arguments;
}
-static QSet<Repository> readRepositories(QXmlStreamReader &reader, bool isDefault, Settings::ParseMode parseMode)
+static QSet<Repository> readRepositories(QXmlStreamReader &reader, bool isDefault, Settings::ParseMode parseMode, QString *displayName = 0)
{
+ qDebug()<<__FUNCTION__;
QSet<Repository> set;
while (reader.readNextStartElement()) {
- if (reader.name() == QLatin1String("Repository")) {
+ if (reader.name() == QLatin1String("DisplayName")) {
+ //remote repository can have also displayname. Needed when creating archive repositories
+ *displayName = reader.readElementText();
+ } else if (reader.name() == QLatin1String("Repository")) {
Repository repo(QString(), isDefault);
while (reader.readNextStartElement()) {
if (reader.name() == QLatin1String("Url")) {
@@ -160,6 +166,8 @@ static QSet<Repository> readRepositories(QXmlStreamReader &reader, bool isDefaul
.arg(reader.name().toString()), parseMode);
}
}
+ if (displayName && !displayName->isEmpty())
+ repo.setArchiveName(*displayName);
set.insert(repo);
} else {
raiseError(reader, QString::fromLatin1("Unexpected element \"%1\".").arg(reader.name().toString()),
@@ -174,6 +182,23 @@ static QSet<Repository> readRepositories(QXmlStreamReader &reader, bool isDefaul
return set;
}
+static QSet<RepositoryCategory> readRepositoryCategories(QXmlStreamReader &reader, bool isDefault, Settings::ParseMode parseMode,
+ QString *repositoryCategoryName)
+{
+ QSet<RepositoryCategory> archiveSet;
+ while (reader.readNextStartElement()) {
+ if (reader.name() == QLatin1String("RemoteRepositories")) {
+ RepositoryCategory archiveRepo;
+ QString displayName;
+ archiveRepo.setRepositories(readRepositories(reader, isDefault, parseMode, &displayName));
+ archiveRepo.setDisplayName(displayName);
+ archiveSet.insert(archiveRepo);
+ } else if (reader.name() == QLatin1String("RepositoryCategoryDisplayname")) {
+ *repositoryCategoryName = reader.readElementText();
+ }
+ }
+ return archiveSet;
+}
// -- Settings::Private
@@ -257,7 +282,7 @@ Settings Settings::fromFileAndPrefix(const QString &path, const QString &prefix,
<< scRepositorySettingsPageVisible << scTargetConfigurationFile
<< scRemoteRepositories << scTranslations << scUrlQueryString << QLatin1String(scControlScript)
<< scCreateLocalRepository << scInstallActionColumnVisible << scSupportsModify << scAllowUnstableComponents
- << scSaveDefaultRepositories;
+ << scSaveDefaultRepositories << scRepositoryCategories;
Settings s;
s.d->m_data.insert(scPrefix, prefix);
@@ -280,11 +305,16 @@ Settings Settings::fromFileAndPrefix(const QString &path, const QString &prefix,
s.setRunProgramArguments(readArgumentAttributes(reader, parseMode, QLatin1String("Argument")));
} else if (name == scRemoteRepositories) {
s.addDefaultRepositories(readRepositories(reader, true, parseMode));
+ } else if (name == scRepositoryCategories) {
+ QString repositoryCategoryName;
+ s.addRepositoryCategories(readRepositoryCategories(reader, true, parseMode, &repositoryCategoryName));
+ if (!repositoryCategoryName.isEmpty()) {
+ s.setRepositoryCategoryDisplayName(repositoryCategoryName);
+ }
} else {
s.d->m_data.insert(name, reader.readElementText(QXmlStreamReader::SkipChildElements));
}
}
-
if (reader.error() != QXmlStreamReader::NoError) {
throw Error(QString::fromLatin1("Error in %1, line %2, column %3: %4").arg(path).arg(reader
.lineNumber()).arg(reader.columnNumber()).arg(reader.errorString()));
@@ -549,6 +579,11 @@ QSet<Repository> Settings::defaultRepositories() const
return variantListToSet<Repository>(d->m_data.values(scRepositories));
}
+QSet<RepositoryCategory> Settings::repositoryCategories() const
+{
+ return variantListToSet<RepositoryCategory>(d->m_data.values(scRepositoryCategories));
+}
+
void Settings::setDefaultRepositories(const QSet<Repository> &repositories)
{
d->m_data.remove(scRepositories);
@@ -561,6 +596,12 @@ void Settings::addDefaultRepositories(const QSet<Repository> &repositories)
d->m_data.insertMulti(scRepositories, QVariant().fromValue(repository));
}
+void Settings::addRepositoryCategories(const QSet<RepositoryCategory> &repositories)
+{
+ foreach (const RepositoryCategory &repository, repositories)
+ d->m_data.insertMulti(scRepositoryCategories, QVariant().fromValue(repository));
+}
+
static bool apply(const RepoHash &updates, QHash<QUrl, Repository> *reposToUpdate)
{
bool update = false;
@@ -767,3 +808,14 @@ void Settings::setSaveDefaultRepositories(bool save)
{
d->m_data.insert(scSaveDefaultRepositories, save);
}
+
+QString Settings::repositoryCategoryDisplayName() const
+{
+ QString displayName = d->m_data.value(QLatin1String(scRepositoryCategoryDisplayName)).toString();
+ return displayName.isEmpty() ? tr("Package categories") : displayName;
+}
+
+void Settings::setRepositoryCategoryDisplayName(const QString& name)
+{
+ d->m_data.insert(scRepositoryCategoryDisplayName, name);
+}
diff --git a/src/libs/installer/settings.h b/src/libs/installer/settings.h
index bc2db655b..0ee58639d 100644
--- a/src/libs/installer/settings.h
+++ b/src/libs/installer/settings.h
@@ -31,6 +31,7 @@
#include "constants.h"
#include "installer_global.h"
+#include "repositorycategory.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QSharedDataPointer>
@@ -114,8 +115,10 @@ public:
QSet<Repository> repositories() const;
QSet<Repository> defaultRepositories() const;
+ QSet<RepositoryCategory> repositoryCategories() const;
void setDefaultRepositories(const QSet<Repository> &repositories);
void addDefaultRepositories(const QSet<Repository> &repositories);
+ void addRepositoryCategories(const QSet<RepositoryCategory> &repositories);
Settings::Update updateDefaultRepositories(const RepoHash &updates);
QSet<Repository> temporaryRepositories() const;
@@ -160,6 +163,9 @@ public:
bool saveDefaultRepositories() const;
void setSaveDefaultRepositories(bool save);
+ QString repositoryCategoryDisplayName() const;
+ void setRepositoryCategoryDisplayName(const QString &displayName);
+
private:
class Private;
QSharedDataPointer<Private> d;