summaryrefslogtreecommitdiffstats
path: root/src/libs/installer
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/installer')
-rw-r--r--src/libs/installer/adminauthorization_x11.cpp234
-rw-r--r--src/libs/installer/binarycontent.h9
-rw-r--r--src/libs/installer/commandlineparser.cpp9
-rw-r--r--src/libs/installer/component.cpp21
-rw-r--r--src/libs/installer/component_p.cpp1
-rw-r--r--src/libs/installer/componentmodel.cpp6
-rw-r--r--src/libs/installer/componentselectionpage_p.cpp64
-rw-r--r--src/libs/installer/componentselectionpage_p.h6
-rw-r--r--src/libs/installer/constants.h5
-rw-r--r--src/libs/installer/downloadarchivesjob.cpp81
-rw-r--r--src/libs/installer/downloadarchivesjob.h11
-rw-r--r--src/libs/installer/elevatedexecuteoperation.cpp2
-rw-r--r--src/libs/installer/installer.pro1
-rw-r--r--src/libs/installer/installiconsoperation.cpp10
-rw-r--r--src/libs/installer/keepaliveobject.cpp7
-rw-r--r--src/libs/installer/lib7z_facade.cpp4
-rw-r--r--src/libs/installer/loggingutils.cpp2
-rw-r--r--src/libs/installer/metadatajob.cpp6
-rw-r--r--src/libs/installer/packagemanagercore.cpp124
-rw-r--r--src/libs/installer/packagemanagercore.h9
-rw-r--r--src/libs/installer/packagemanagercore_p.cpp104
-rw-r--r--src/libs/installer/packagemanagercore_p.h12
-rw-r--r--src/libs/installer/packagemanagergui.cpp12
-rw-r--r--src/libs/installer/performinstallationform.cpp8
-rw-r--r--src/libs/installer/qsettingswrapper.cpp4
-rw-r--r--src/libs/installer/remoteclient_p.h4
-rw-r--r--src/libs/installer/selfrestartoperation.cpp2
-rw-r--r--src/libs/installer/settingsoperation.cpp2
-rw-r--r--src/libs/installer/utils.cpp8
29 files changed, 368 insertions, 400 deletions
diff --git a/src/libs/installer/adminauthorization_x11.cpp b/src/libs/installer/adminauthorization_x11.cpp
index 14691c9de..f4951d523 100644
--- a/src/libs/installer/adminauthorization_x11.cpp
+++ b/src/libs/installer/adminauthorization_x11.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -28,41 +28,18 @@
#include "adminauthorization.h"
-#include <QtCore/QFile>
-#include <QtCore/QRegExp>
-#include <QDebug>
+#include "globals.h"
+#include <QDebug>
#include <QApplication>
-#include <QInputDialog>
#include <QMessageBox>
+#include <QProcess>
-#include <cstdlib>
-#include <sys/resource.h>
#include <unistd.h>
-#include <fcntl.h>
-
-#ifdef Q_OS_LINUX
-#include <linux/limits.h>
-#include <pty.h>
-#else
-#ifdef Q_OS_FREEBSD
-#include <libutil.h>
-#include <signal.h>
-#else
-#include <util.h>
-#endif
-#endif
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <errno.h>
#include <iostream>
-#include "globals.h"
-
-#define SU_COMMAND "/usr/bin/sudo"
-//#define SU_COMMAND "/bin/echo"
+#define PKEXEC_COMMAND "/usr/bin/pkexec"
namespace QInstaller {
@@ -72,24 +49,6 @@ namespace QInstaller {
\internal
*/
-static QString getPassword(QWidget *parent)
-{
- if (qobject_cast<QApplication*> (qApp) != 0) {
- bool ok = false;
- const QString result = QInputDialog::getText(parent, QObject::tr("Authorization required"),
- QObject::tr("Enter your password to authorize for sudo:"),
- QLineEdit::Password, QString(), &ok);
- return ok ? result : QString();
- } else {
- std::cout << QObject::tr("Authorization required").toStdString() << std::endl;
- std::cout << QObject::tr("Enter your password to authorize for sudo:").toStdString()
- << std::endl;
- std::string password;
- std::cin >> password;
- return QString::fromStdString(password);
- }
-}
-
static void printError(QWidget *parent, const QString &value)
{
if (qobject_cast<QApplication*> (qApp) != 0) {
@@ -105,184 +64,21 @@ bool AdminAuthorization::execute(QWidget *parent, const QString &program, const
const QString fallback = program + QLatin1String(" ") + arguments.join(QLatin1String(" "));
qCDebug(QInstaller::lcServer) << "Fallback:" << fallback;
- // as we cannot pipe the password to su in QProcess, we need to setup a pseudo-terminal for it
- int masterFD = -1;
- int slaveFD = -1;
- char ptsn[ PATH_MAX ];
+ QProcess process;
+ process.setProcessChannelMode(QProcess::MergedChannels);
+ process.start(QLatin1String(PKEXEC_COMMAND), QStringList() << program << arguments, QIODevice::ReadOnly);
- if (::openpty(&masterFD, &slaveFD, ptsn, 0, 0))
- return false;
-
- masterFD = ::posix_openpt(O_RDWR | O_NOCTTY);
- if (masterFD < 0)
- return false;
-
- const QByteArray ttyName = ::ptsname(masterFD);
-
- if (::grantpt(masterFD)) {
- ::close(masterFD);
- return false;
- }
-
- ::revoke(ttyName);
- ::unlockpt(masterFD);
-
- slaveFD = ::open(ttyName, O_RDWR | O_NOCTTY);
- if (slaveFD < 0) {
- ::close(masterFD);
+ if (!process.waitForStarted() || !process.waitForFinished(-1)) {
+ printError(parent, process.errorString());
+ if (process.state() > QProcess::NotRunning)
+ process.kill();
return false;
}
-
- ::fcntl(masterFD, F_SETFD, FD_CLOEXEC);
- ::fcntl(slaveFD, F_SETFD, FD_CLOEXEC);
- int pipedData[2];
- if (pipe(pipedData) != 0)
- return false;
-
- int flags = ::fcntl(pipedData[0], F_GETFL);
- if (flags != -1)
- ::fcntl(pipedData[0], F_SETFL, flags | O_NONBLOCK);
-
- flags = ::fcntl(masterFD, F_GETFL);
- if (flags != -1)
- ::fcntl(masterFD, F_SETFL, flags | O_NONBLOCK);
-
- pid_t child = fork();
-
- if (child < -1) {
- ::close(masterFD);
- ::close(slaveFD);
- ::close(pipedData[0]);
- ::close(pipedData[1]);
- return false;
- }
-
- // parent process
- else if (child > 0) {
- ::close(slaveFD);
- //close writing end of pipe
- ::close(pipedData[1]);
-
- QRegExp re(QLatin1String("[Pp]assword.*:"));
- QByteArray data;
- QByteArray errData;
- int bytes = 0;
- int errBytes = 0;
- char buf[1024];
- char errBuf[1024];
- int status;
- bool statusValid = false;
- while (bytes >= 0) {
- const pid_t waitResult = ::waitpid(child, &status, WNOHANG);
- if (waitResult == -1) {
- break;
- }
- if (waitResult == child) {
- statusValid = true;
- break;
- }
- bytes = ::read(masterFD, buf, 1023);
- if (bytes == -1 && errno == EAGAIN)
- bytes = 0;
- else if (bytes > 0)
- data.append(buf, bytes);
- errBytes = ::read(pipedData[0], errBuf, 1023);
- if (errBytes > 0)
- {
- errData.append(errBuf, errBytes);
- errBytes=0;
- }
- if (bytes > 0) {
- const QString line = QString::fromLatin1(data);
- if (re.indexIn(line) != -1) {
- const QString password = getPassword(parent);
- if (password.isEmpty()) {
- QByteArray pwd = password.toLatin1();
- for (int i = 0; i < 3; ++i) {
- ::write(masterFD, pwd.data(), pwd.length());
- ::write(masterFD, "\n", 1);
- }
- return false;
- }
- QByteArray pwd = password.toLatin1();
- ::write(masterFD, pwd.data(), pwd.length());
- ::write(masterFD, "\n", 1);
- ::read(masterFD, buf, pwd.length() + 1);
- }
- }
- if (bytes == 0)
- ::usleep(100000);
- }
-
- while (true) {
- errBytes = ::read(pipedData[0], errBuf, 1023);
- if (errBytes == -1 && errno == EAGAIN) {
- ::usleep(100000);
- continue;
- }
-
- if (errBytes <= 0)
- break;
-
- errData.append(errBuf, errBytes);
- }
-
- const bool success = statusValid && WIFEXITED(status) && WEXITSTATUS(status) == 0;
-
- if (!success && !errData.isEmpty()) {
- printError(parent, QString::fromLocal8Bit(errData.constData()));
- }
-
- ::close(pipedData[0]);
- return success;
- }
-
- // child process
- else {
- ::close(pipedData[0]);
- // Reset signal handlers
- for (int sig = 1; sig < NSIG; ++sig)
- signal(sig, SIG_DFL);
- signal(SIGHUP, SIG_IGN);
-
- ::setsid();
-
- ::ioctl(slaveFD, TIOCSCTTY, 1);
- int pgrp = ::getpid();
- ::tcsetpgrp(slaveFD, pgrp);
-
- ::dup2(slaveFD, 0);
- ::dup2(slaveFD, 1);
- ::dup2(pipedData[1], 2);
-
- // close all file descriptors
- struct rlimit rlp;
- getrlimit(RLIMIT_NOFILE, &rlp);
- for (int i = 3; i < static_cast<int>(rlp.rlim_cur); ++i)
- ::close(i);
-
- char **argp = (char **) ::malloc((arguments.count() + 4) * sizeof(char *));
- QList<QByteArray> args;
- args.push_back(SU_COMMAND);
- args.push_back("-b");
- args.push_back(program.toLocal8Bit());
- for (QStringList::const_iterator it = arguments.begin(); it != arguments.end(); ++it)
- args.push_back(it->toLocal8Bit());
-
- int i = 0;
- for (QList<QByteArray>::iterator it = args.begin(); it != args.end(); ++it, ++i)
- argp[i] = it->data();
- argp[i] = 0;
-
- ::unsetenv("LANG");
- ::unsetenv("LC_ALL");
-
- int exitStatus = 0;
- if (::execv(SU_COMMAND, argp) == -1)
- exitStatus = -errno;
- _exit(exitStatus);
+ if (process.exitCode() != EXIT_SUCCESS) {
+ printError(parent, QLatin1String(process.readAll()));
return false;
}
+ return true;
}
// has no guarantee to work
diff --git a/src/libs/installer/binarycontent.h b/src/libs/installer/binarycontent.h
index a21cd69e7..7d50c0e28 100644
--- a/src/libs/installer/binarycontent.h
+++ b/src/libs/installer/binarycontent.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -48,6 +48,13 @@ public:
static const qint64 MagicUpdaterMarker = 0x12023235UL;
static const qint64 MagicPackageManagerMarker = 0x12023236UL;
+ // additional distinguishers only used at runtime, not written to the binary itself
+ enum MagicMarkerSupplement {
+ Default = 0x0,
+ OfflineGenerator = 0x1,
+ PackageViewer = 0x2
+ };
+
// the cookie put at the end of the file
static const quint64 MagicCookie = 0xc2630a1c99d668f8LL; // binary
static const quint64 MagicCookieDat = 0xc2630a1c99d668f9LL; // data
diff --git a/src/libs/installer/commandlineparser.cpp b/src/libs/installer/commandlineparser.cpp
index 59d42eefc..4bfc4ad3a 100644
--- a/src/libs/installer/commandlineparser.cpp
+++ b/src/libs/installer/commandlineparser.cpp
@@ -59,6 +59,9 @@ CommandLineParser::CommandLineParser()
.arg(CommandLineOptions::scListShort, CommandLineOptions::scListLong)
+ indent + QString::fromLatin1("%1, %2 - search available packages - <regexp>\n")
.arg(CommandLineOptions::scSearchShort, CommandLineOptions::scSearchLong)
+ + indent + indent + QString::fromLatin1("Note: The --%1 option can be used to specify\n")
+ .arg(CommandLineOptions::scFilterPackagesLong)
+ + indent + indent + QLatin1String("additional filters for the search operation\n")
+ indent + QString::fromLatin1("%1, %2 - create offline installer from selected packages - <pkg ...>\n")
.arg(CommandLineOptions::scCreateOfflineShort, CommandLineOptions::scCreateOfflineLong)
+ indent + QString::fromLatin1("%1, %2 - uninstall all packages and remove entire program directory")
@@ -161,6 +164,12 @@ CommandLineParser::CommandLineParser()
<< CommandLineOptions::scCreateLocalRepositoryShort << CommandLineOptions::scCreateLocalRepositoryLong,
QLatin1String("Create a local repository inside the installation directory. This option "
"has no effect on online installers.")));
+ addOptionWithContext(QCommandLineOption(QStringList()
+ << CommandLineOptions::scFilterPackagesShort << CommandLineOptions::scFilterPackagesLong,
+ QLatin1String("[CLI] Comma separated list of additional key-value pair filters used to query packages with the "
+ "search command. The keys can be any of the possible package information elements, like "
+ "\"DisplayName\" and \"Description\"."),
+ QLatin1String("element=regex,...")), CommandLineOnly);
// Message query options
addOptionWithContext(QCommandLineOption(QStringList() << CommandLineOptions::scAcceptMessageQueryShort
diff --git a/src/libs/installer/component.cpp b/src/libs/installer/component.cpp
index 3b8894b03..6e3856502 100644
--- a/src/libs/installer/component.cpp
+++ b/src/libs/installer/component.cpp
@@ -301,11 +301,14 @@ void Component::loadDataFromPackage(const KDUpdater::LocalPackage &package)
setValue(scCurrentState, scInstalled);
setValue(scCheckable, package.checkable ? scTrue : scFalse);
setValue(scExpandedByDefault, package.expandedByDefault ? scTrue : scFalse);
+ setValue(scContentSha1, package.contentSha1);
}
/*!
Sets variables according to the values set in the package.xml file of \a package.
Also loads UI files, licenses and translations if they are referenced in the package.xml.
+ If the \c PackageManagerCore object of this component is run as package viewer, then
+ only sets the variables without loading referenced files.
*/
void Component::loadDataFromPackage(const Package &package)
{
@@ -342,6 +345,10 @@ void Component::loadDataFromPackage(const Package &package)
if (PackageManagerCore::noForceInstallation())
forced = scFalse;
setValue(scForcedInstallation, forced);
+ setValue(scContentSha1, package.data(scContentSha1).toString());
+
+ if (d->m_core->isPackageViewer())
+ return;
setLocalTempPath(QInstaller::pathFromUrl(package.packageSource().url));
const QStringList uis = package.data(QLatin1String("UserInterfaces")).toString()
@@ -369,16 +376,20 @@ quint64 Component::updateUncompressedSize()
{
quint64 size = 0;
- if (installAction() == ComponentModelHelper::Install
- || installAction() == ComponentModelHelper::KeepInstalled) {
+ const bool installOrKeepInstalled = (installAction() == ComponentModelHelper::Install
+ || installAction() == ComponentModelHelper::KeepInstalled);
+
+ if (installOrKeepInstalled)
size = d->m_vars.value(scUncompressedSize).toLongLong();
- }
foreach (Component* comp, d->m_allChildComponents)
size += comp->updateUncompressedSize();
setValue(scUncompressedSizeSum, QString::number(size));
- setData(humanReadableSize(size), UncompressedSize);
+ if (size == 0 && !installOrKeepInstalled)
+ setData(QVariant(), UncompressedSize);
+ else
+ setData(humanReadableSize(size), UncompressedSize);
return size;
}
@@ -1643,7 +1654,7 @@ void Component::updateModelData(const QString &key, const QString &data)
}
if (isUnstable()) {
tooltipText += QLatin1String("<br>") + tr("There was an error loading the selected component. "
- "This component can not be installed.");
+ "This component cannot be installed.");
}
// replace {external-link}='' fields in component description with proper link tags
tooltipText.replace(QRegularExpression(QLatin1String("{external-link}='(.*?)'")),
diff --git a/src/libs/installer/component_p.cpp b/src/libs/installer/component_p.cpp
index 8533d8e4c..0f74e423c 100644
--- a/src/libs/installer/component_p.cpp
+++ b/src/libs/installer/component_p.cpp
@@ -54,6 +54,7 @@ ComponentPrivate::ComponentPrivate(PackageManagerCore *core, Component *qq)
, m_autoCreateOperations(true)
, m_operationsCreatedSuccessfully(true)
, m_updateIsAvailable(false)
+ , m_unstable(false)
{
}
diff --git a/src/libs/installer/componentmodel.cpp b/src/libs/installer/componentmodel.cpp
index aab487b45..642828ad7 100644
--- a/src/libs/installer/componentmodel.cpp
+++ b/src/libs/installer/componentmodel.cpp
@@ -260,9 +260,9 @@ bool ComponentModel::setData(const QModelIndex &index, const QVariant &value, in
newValue = (oldValue == Qt::Checked) ? Qt::Unchecked : Qt::Checked;
}
QSet<QModelIndex> changed = updateCheckedState(nodes << component, newValue);
- foreach (const QModelIndex &index, changed) {
- emit dataChanged(index, index);
- emit checkStateChanged(index);
+ foreach (const QModelIndex &changedIndex, changed) {
+ emit dataChanged(changedIndex, changedIndex);
+ emit checkStateChanged(changedIndex);
}
updateAndEmitModelState(); // update the internal state
} else {
diff --git a/src/libs/installer/componentselectionpage_p.cpp b/src/libs/installer/componentselectionpage_p.cpp
index 37dc0f13e..a180888d1 100644
--- a/src/libs/installer/componentselectionpage_p.cpp
+++ b/src/libs/installer/componentselectionpage_p.cpp
@@ -49,6 +49,7 @@
#include <QFileDialog>
#include <QStackedLayout>
#include <QStackedWidget>
+#include <QToolBox>
namespace QInstaller {
@@ -66,19 +67,29 @@ ComponentSelectionPagePrivate::ComponentSelectionPagePrivate(ComponentSelectionP
, m_updaterModel(m_core->updaterComponentModel())
, m_currentModel(m_allModel)
, m_allowCompressedRepositoryInstall(false)
+ , m_toolBox(nullptr)
+ , m_descriptionBaseWidget(nullptr)
, m_categoryWidget(Q_NULLPTR)
+ , m_categoryLayoutVisible(false)
{
m_treeView->setObjectName(QLatin1String("ComponentsTreeView"));
- QVBoxLayout *descriptionVLayout = new QVBoxLayout;
+ m_descriptionBaseWidget = new QWidget(q);
+ m_descriptionBaseWidget->setObjectName(QLatin1String("DescriptionBaseWidget"));
+
+ QVBoxLayout *descriptionVLayout = new QVBoxLayout(m_descriptionBaseWidget);
descriptionVLayout->setObjectName(QLatin1String("DescriptionLayout"));
+ descriptionVLayout->setContentsMargins(0, 0, 0, 0);
+
+ m_toolBox = new QToolBox(q);
+ m_toolBox->setObjectName(QLatin1String("ToolBox"));
QScrollArea *descriptionScrollArea = new QScrollArea(q);
descriptionScrollArea->setWidgetResizable(true);
descriptionScrollArea->setFrameShape(QFrame::NoFrame);
descriptionScrollArea->setObjectName(QLatin1String("DescriptionScrollArea"));
- m_descriptionLabel = new QLabel(q);
+ m_descriptionLabel = new QLabel(m_descriptionBaseWidget);
m_descriptionLabel->setWordWrap(true);
m_descriptionLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
m_descriptionLabel->setOpenExternalLinks(true);
@@ -87,8 +98,7 @@ ComponentSelectionPagePrivate::ComponentSelectionPagePrivate(ComponentSelectionP
descriptionScrollArea->setWidget(m_descriptionLabel);
descriptionVLayout->addWidget(descriptionScrollArea);
- m_sizeLabel = new QLabel(q);
- m_sizeLabel->setMargin(5);
+ m_sizeLabel = new QLabel(m_descriptionBaseWidget);
m_sizeLabel->setWordWrap(true);
m_sizeLabel->setObjectName(QLatin1String("ComponentSizeLabel"));
descriptionVLayout->addWidget(m_sizeLabel);
@@ -100,14 +110,14 @@ ComponentSelectionPagePrivate::ComponentSelectionPagePrivate(ComponentSelectionP
if (m_core->isInstaller()) {
m_checkDefault->setObjectName(QLatin1String("SelectDefaultComponentsButton"));
m_checkDefault->setShortcut(QKeySequence(ComponentSelectionPage::tr("Alt+A",
- "select default components")));
+ "Select default components")));
m_checkDefault->setText(ComponentSelectionPage::tr("Def&ault"));
m_checkDefault->setToolTip(ComponentSelectionPage::tr("Select default components in the tree view."));
} else {
m_checkDefault->setEnabled(false);
m_checkDefault->setObjectName(QLatin1String("ResetComponentsButton"));
m_checkDefault->setShortcut(QKeySequence(ComponentSelectionPage::tr("Alt+R",
- "reset to already installed components")));
+ "Reset to already installed components")));
m_checkDefault->setText(ComponentSelectionPage::tr("&Reset"));
m_checkDefault->setToolTip(
ComponentSelectionPage::tr("Reset all components to their original selection state in the tree view."));
@@ -119,7 +129,7 @@ ComponentSelectionPagePrivate::ComponentSelectionPagePrivate(ComponentSelectionP
this, &ComponentSelectionPagePrivate::selectAll);
m_checkAll->setObjectName(QLatin1String("SelectAllComponentsButton"));
m_checkAll->setShortcut(QKeySequence(ComponentSelectionPage::tr("Alt+S",
- "select all components")));
+ "Select all components")));
m_checkAll->setText(ComponentSelectionPage::tr("&Select All"));
m_checkAll->setToolTip(ComponentSelectionPage::tr("Select all components in the tree view."));
buttonHLayout->addWidget(m_checkAll);
@@ -129,7 +139,7 @@ ComponentSelectionPagePrivate::ComponentSelectionPagePrivate(ComponentSelectionP
this, &ComponentSelectionPagePrivate::deselectAll);
m_uncheckAll->setObjectName(QLatin1String("DeselectAllComponentsButton"));
m_uncheckAll->setShortcut(QKeySequence(ComponentSelectionPage::tr("Alt+D",
- "deselect all components")));
+ "Deselect all components")));
m_uncheckAll->setText(ComponentSelectionPage::tr("&Deselect All"));
m_uncheckAll->setToolTip(ComponentSelectionPage::tr("Deselect all components in the tree view."));
buttonHLayout->addWidget(m_uncheckAll);
@@ -151,11 +161,11 @@ ComponentSelectionPagePrivate::ComponentSelectionPagePrivate(ComponentSelectionP
QWidget *mainStackedWidget = new QWidget();
m_mainGLayout = new QGridLayout(mainStackedWidget);
- m_mainGLayout->addLayout(buttonHLayout, 0, 1);
- m_mainGLayout->addLayout(treeViewVLayout, 1, 1);
- m_mainGLayout->addLayout(descriptionVLayout, 1, 2);
- m_mainGLayout->setColumnStretch(1, 3);
- m_mainGLayout->setColumnStretch(2, 2);
+ m_mainGLayout->addLayout(buttonHLayout, 0, 0);
+ m_mainGLayout->addLayout(treeViewVLayout, 1, 0);
+ m_mainGLayout->addWidget(m_descriptionBaseWidget, 1, 1);
+ m_mainGLayout->setColumnStretch(0, 3);
+ m_mainGLayout->setColumnStretch(1, 2);
m_stackedLayout = new QStackedLayout(q);
m_stackedLayout->addWidget(mainStackedWidget);
@@ -227,13 +237,13 @@ void ComponentSelectionPagePrivate::setupCategoryLayout()
vLayout->setContentsMargins(0, 0, 0, 0);
m_categoryWidget->setLayout(vLayout);
m_categoryGroupBox = new QGroupBox(q);
- m_categoryGroupBox->setTitle(m_core->settings().repositoryCategoryDisplayName());
m_categoryGroupBox->setObjectName(QLatin1String("CategoryGroupBox"));
QVBoxLayout *categoryLayout = new QVBoxLayout(m_categoryGroupBox);
QPushButton *fetchCategoryButton = new QPushButton(tr("Filter"));
fetchCategoryButton->setObjectName(QLatin1String("FetchCategoryButton"));
+ fetchCategoryButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
fetchCategoryButton->setToolTip(
- ComponentSelectionPage::tr("Filter the enabled repository categories to selection."));
+ ComponentSelectionPage::tr("Filter the enabled repository categories"));
connect(fetchCategoryButton, &QPushButton::clicked, this,
&ComponentSelectionPagePrivate::fetchRepositoryCategories);
@@ -249,16 +259,29 @@ void ComponentSelectionPagePrivate::setupCategoryLayout()
vLayout->addWidget(m_categoryGroupBox);
vLayout->addStretch();
- m_mainGLayout->addWidget(m_categoryWidget, 1, 0);
+ m_toolBox->insertItem(1, m_categoryWidget, m_core->settings().repositoryCategoryDisplayName());
}
void ComponentSelectionPagePrivate::showCategoryLayout(bool show)
{
+ if (!show && !m_categoryWidget)
+ return;
+
+ if (show == m_categoryLayoutVisible)
+ return;
+
+ setupCategoryLayout();
if (show) {
- setupCategoryLayout();
+ m_mainGLayout->removeWidget(m_descriptionBaseWidget);
+ m_toolBox->insertItem(0, m_descriptionBaseWidget, tr("Component Information"));
+ m_mainGLayout->addWidget(m_toolBox, 1, 1);
+ } else {
+ m_toolBox->removeItem(0);
+ m_mainGLayout->removeWidget(m_toolBox);
+ m_mainGLayout->addWidget(m_descriptionBaseWidget, 1, 1);
}
- if (m_categoryWidget)
- m_categoryWidget->setVisible(show);
+ m_toolBox->setVisible(show);
+ m_categoryLayoutVisible = show;
}
void ComponentSelectionPagePrivate::updateTreeView()
@@ -395,10 +418,9 @@ void ComponentSelectionPagePrivate::fetchRepositoryCategories()
{
updateWidgetVisibility(true);
- QCheckBox *checkbox;
QList<QCheckBox*> checkboxes = m_categoryGroupBox->findChildren<QCheckBox *>();
for (int i = 0; i < checkboxes.count(); i++) {
- checkbox = checkboxes.at(i);
+ QCheckBox *checkbox = checkboxes.at(i);
enableRepositoryCategory(checkbox->objectName(), checkbox->isChecked());
}
diff --git a/src/libs/installer/componentselectionpage_p.h b/src/libs/installer/componentselectionpage_p.h
index 37f808286..d2d30e3f0 100644
--- a/src/libs/installer/componentselectionpage_p.h
+++ b/src/libs/installer/componentselectionpage_p.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -46,6 +46,7 @@ class QVBoxLayout;
class QHBoxLayout;
class QGridLayout;
class QStackedLayout;
+class QToolBox;
namespace QInstaller {
@@ -88,6 +89,8 @@ private:
ComponentSelectionPage *q;
PackageManagerCore *m_core;
QTreeView *m_treeView;
+ QToolBox *m_toolBox;
+ QWidget *m_descriptionBaseWidget;
QLabel *m_sizeLabel;
QLabel *m_descriptionLabel;
QPushButton *m_checkAll;
@@ -99,6 +102,7 @@ private:
QProgressBar *m_progressBar;
QGridLayout *m_mainGLayout;
bool m_allowCompressedRepositoryInstall;
+ bool m_categoryLayoutVisible;
ComponentModel *m_allModel;
ComponentModel *m_updaterModel;
ComponentModel *m_currentModel;
diff --git a/src/libs/installer/constants.h b/src/libs/installer/constants.h
index 42b14ce63..0e16d4c4b 100644
--- a/src/libs/installer/constants.h
+++ b/src/libs/installer/constants.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2020 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -67,6 +67,7 @@ static const QLatin1String scUncompressedSizeSum("UncompressedSizeSum");
static const QLatin1String scRequiresAdminRights("RequiresAdminRights");
static const QLatin1String scOfflineBinaryName("OfflineBinaryName");
static const QLatin1String scSHA1("SHA1");
+static const QLatin1String scContentSha1("ContentSha1");
// constants used throughout the components class
static const QLatin1String scVirtual("Virtual");
@@ -202,6 +203,8 @@ static const QLatin1String scCreateLocalRepositoryShort("cl");
static const QLatin1String scCreateLocalRepositoryLong("create-local-repository");
static const QLatin1String scNoDefaultInstallationShort("nd");
static const QLatin1String scNoDefaultInstallationLong("no-default-installations");
+static const QLatin1String scFilterPackagesShort("fp");
+static const QLatin1String scFilterPackagesLong("filter-packages");
// Developer options
static const QLatin1String scScriptShort("s");
diff --git a/src/libs/installer/downloadarchivesjob.cpp b/src/libs/installer/downloadarchivesjob.cpp
index 5dbccc0b6..c7ba9dc80 100644
--- a/src/libs/installer/downloadarchivesjob.cpp
+++ b/src/libs/installer/downloadarchivesjob.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -32,6 +32,7 @@
#include "messageboxhandler.h"
#include "packagemanagercore.h"
#include "utils.h"
+#include "fileutils.h"
#include "filedownloader.h"
#include "filedownloaderfactory.h"
@@ -55,6 +56,8 @@ DownloadArchivesJob::DownloadArchivesJob(PackageManagerCore *core)
, m_canceled(false)
, m_lastFileProgress(0)
, m_progressChangedTimerId(0)
+ , m_totalSizeToDownload(0)
+ , m_totalSizeDownloaded(0)
{
setCapabilities(Cancelable);
}
@@ -79,10 +82,19 @@ void DownloadArchivesJob::setArchivesToDownload(const QList<QPair<QString, QStri
}
/*!
+ Sets the expected total size of archives to download to \a total.
+*/
+void DownloadArchivesJob::setExpectedTotalSize(quint64 total)
+{
+ m_totalSizeToDownload = total;
+}
+
+/*!
\reimp
*/
void DownloadArchivesJob::doStart()
{
+ m_totalDownloadSpeedTimer.start();
m_archivesDownloaded = 0;
fetchNextArchiveHash();
}
@@ -198,6 +210,70 @@ void DownloadArchivesJob::timerEvent(QTimerEvent *event)
}
/*!
+ Builds a textual representation of the total download \a status and
+ emits the \c {downloadStatusChanged()} signal.
+*/
+void DownloadArchivesJob::onDownloadStatusChanged(const QString &status)
+{
+ if (!m_downloader || m_canceled) {
+ emit downloadStatusChanged(status);
+ return;
+ }
+
+ QString extendedStatus;
+ quint64 currentDownloaded = m_totalSizeDownloaded + m_downloader->getBytesReceived();
+ if (m_totalSizeToDownload > 0) {
+ QString bytesReceived = humanReadableSize(currentDownloaded);
+ const QString bytesToReceive = humanReadableSize(m_totalSizeToDownload);
+
+ // 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());
+
+ extendedStatus = tr("%1 of %2").arg(bytesReceived, bytesToReceive);
+ } else if (currentDownloaded > 0) {
+ extendedStatus = tr("%1 downloaded.").arg(humanReadableSize(currentDownloaded));
+ }
+
+ const quint64 totalDownloadSpeed = currentDownloaded
+ / double(m_totalDownloadSpeedTimer.elapsed() / 1000);
+
+ if (m_totalSizeToDownload > 0 && totalDownloadSpeed > 0) {
+ const qint64 time = (m_totalSizeToDownload - currentDownloaded) / totalDownloadSpeed;
+
+ 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 = tr("%n day(s), ", "", d);
+
+ QString hours;
+ if (h > 0)
+ hours = tr("%n hour(s), ", "", h);
+
+ QString minutes;
+ if (m > 0)
+ minutes = tr("%n minute(s)", "", m);
+
+ QString seconds;
+ if (s >= 0 && minutes.isEmpty()) {
+ s = (s <= 0 ? 1 : s);
+ seconds = tr("%n second(s)", "", s);
+ }
+ extendedStatus += tr(" - %1%2%3%4 remaining.").arg(days, hours, minutes, seconds);
+ } else {
+ extendedStatus += tr(" - unknown time remaining.");
+ }
+
+ emit downloadStatusChanged(QLatin1String("Archive: ") + status
+ + QLatin1String("<br>Total: ") + extendedStatus);
+}
+
+/*!
Registers the just downloaded file in the installer's file system.
*/
void DownloadArchivesJob::registerFile()
@@ -224,6 +300,7 @@ void DownloadArchivesJob::registerFile()
}
} else {
++m_archivesDownloaded;
+ m_totalSizeDownloaded += QFile(m_downloader->downloadedFileName()).size();
if (m_progressChangedTimerId) {
killTimer(m_progressChangedTimerId);
m_progressChangedTimerId = 0;
@@ -295,7 +372,7 @@ KDUpdater::FileDownloader *DownloadArchivesJob::setupDownloader(const QString &s
connect(downloader, &FileDownloader::downloadCanceled, this, &DownloadArchivesJob::downloadCanceled);
connect(downloader, &FileDownloader::downloadAborted, this, &DownloadArchivesJob::downloadFailed,
Qt::QueuedConnection);
- connect(downloader, &FileDownloader::downloadStatus, this, &DownloadArchivesJob::downloadStatusChanged);
+ connect(downloader, &FileDownloader::downloadStatus, this, &DownloadArchivesJob::onDownloadStatusChanged);
if (FileDownloaderFactory::isSupportedScheme(scheme)) {
downloader->setDownloadedFileName(component->localTempPath() + QLatin1Char('/')
diff --git a/src/libs/installer/downloadarchivesjob.h b/src/libs/installer/downloadarchivesjob.h
index 8f2392064..bd764e01c 100644
--- a/src/libs/installer/downloadarchivesjob.h
+++ b/src/libs/installer/downloadarchivesjob.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -32,6 +32,7 @@
#include "job.h"
#include <QtCore/QPair>
+#include <QtCore/QElapsedTimer>
QT_BEGIN_NAMESPACE
class QTimerEvent;
@@ -56,6 +57,7 @@ public:
int numberOfDownloads() const { return m_archivesDownloaded; }
void setArchivesToDownload(const QList<QPair<QString, QString> > &archives);
+ void setExpectedTotalSize(quint64 total);
Q_SIGNALS:
void progressChanged(double progress);
@@ -67,6 +69,9 @@ protected:
void doCancel();
void timerEvent(QTimerEvent *event);
+public Q_SLOTS:
+ void onDownloadStatusChanged(const QString &status);
+
protected Q_SLOTS:
void registerFile();
void downloadCanceled();
@@ -92,6 +97,10 @@ private:
QByteArray m_currentHash;
double m_lastFileProgress;
int m_progressChangedTimerId;
+
+ quint64 m_totalSizeToDownload;
+ quint64 m_totalSizeDownloaded;
+ QElapsedTimer m_totalDownloadSpeedTimer;
};
} // namespace QInstaller
diff --git a/src/libs/installer/elevatedexecuteoperation.cpp b/src/libs/installer/elevatedexecuteoperation.cpp
index 4ca9a8e59..fb1778fe0 100644
--- a/src/libs/installer/elevatedexecuteoperation.cpp
+++ b/src/libs/installer/elevatedexecuteoperation.cpp
@@ -169,7 +169,7 @@ int ElevatedExecuteOperation::Private::run(QStringList &arguments, const Operati
<< workingDirectory;
}
- QProcessEnvironment penv;
+ QProcessEnvironment penv = QProcessEnvironment::systemEnvironment();
// there is no way to serialize a QProcessEnvironment properly other than per mangled QStringList:
// (i.e. no other way to list all keys)
process->setEnvironment(KDUpdater::Environment::instance().applyTo(penv).toStringList());
diff --git a/src/libs/installer/installer.pro b/src/libs/installer/installer.pro
index bc4fcbb39..c28a840bd 100644
--- a/src/libs/installer/installer.pro
+++ b/src/libs/installer/installer.pro
@@ -230,6 +230,7 @@ unix {
}
LIBS += -l7z
+CONFIG(libarchive): LIBS += -llibarchive
win32 {
SOURCES += adminauthorization_win.cpp sysinfo_win.cpp
diff --git a/src/libs/installer/installiconsoperation.cpp b/src/libs/installer/installiconsoperation.cpp
index 9443b7f71..de1ddcc4f 100644
--- a/src/libs/installer/installiconsoperation.cpp
+++ b/src/libs/installer/installiconsoperation.cpp
@@ -134,8 +134,8 @@ bool InstallIconsOperation::performOperation()
if (status == PackageManagerCore::Canceled || status == PackageManagerCore::Failure)
return true;
- const QString &source = it.next();
- QString target = targetDir.absoluteFilePath(sourceDir.relativeFilePath(source));
+ const QString &source2 = it.next();
+ QString target = targetDir.absoluteFilePath(sourceDir.relativeFilePath(source2));
emit outputTextChanged(target);
@@ -185,7 +185,7 @@ bool InstallIconsOperation::performOperation()
}
// copy the file to its new location
- QFile cf(source);
+ QFile cf(source2);
if (!cf.copy(target)) {
setError(UserDefinedError);
setErrorString(tr("Failed to copy file \"%1\": %2").arg(
@@ -193,8 +193,8 @@ bool InstallIconsOperation::performOperation()
undoOperation();
return false;
}
- deleteFileNowOrLater(source);
- files.push_back(source);
+ deleteFileNowOrLater(source2);
+ files.push_back(source2);
files.push_back(target);
setValue(QLatin1String("files"), files);
} else if (fi.isDir() && !QDir(target).exists()) {
diff --git a/src/libs/installer/keepaliveobject.cpp b/src/libs/installer/keepaliveobject.cpp
index 94e91efd8..18ec9743a 100644
--- a/src/libs/installer/keepaliveobject.cpp
+++ b/src/libs/installer/keepaliveobject.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -48,7 +48,12 @@ KeepAliveObject::KeepAliveObject()
void KeepAliveObject::start()
{
+ if (m_timer)
+ delete m_timer;
m_timer = new QTimer(this);
+
+ if (m_socket)
+ delete m_socket;
m_socket = new QLocalSocket(this);
connect(m_timer, &QTimer::timeout, [this]() {
diff --git a/src/libs/installer/lib7z_facade.cpp b/src/libs/installer/lib7z_facade.cpp
index fc6ac7ae4..2f33c95e3 100644
--- a/src/libs/installer/lib7z_facade.cpp
+++ b/src/libs/installer/lib7z_facade.cpp
@@ -261,7 +261,7 @@ QString errorMessageFrom7zResult(const LONG &extractResult)
if (!lastError().isEmpty())
return lastError();
- QString errorMessage = QCoreApplication::translate("Lib7z", "internal code: %1");
+ QString errorMessage = QCoreApplication::translate("Lib7z", "Internal code: %1");
switch (extractResult) {
case S_OK:
qFatal("S_OK value is not a valid error code.");
@@ -282,7 +282,7 @@ QString errorMessageFrom7zResult(const LONG &extractResult)
errorMessage = errorMessage.arg(QLatin1String("STG_E_INVALIDFUNCTION"));
break;
case E_OUTOFMEMORY:
- errorMessage = QCoreApplication::translate("Lib7z", "not enough memory");
+ errorMessage = QCoreApplication::translate("Lib7z", "Not enough memory");
break;
case E_INVALIDARG:
errorMessage = errorMessage.arg(QLatin1String("E_INVALIDARG"));
diff --git a/src/libs/installer/loggingutils.cpp b/src/libs/installer/loggingutils.cpp
index 0ebba10db..45f7aab1b 100644
--- a/src/libs/installer/loggingutils.cpp
+++ b/src/libs/installer/loggingutils.cpp
@@ -259,7 +259,7 @@ void LoggingHandler::printComponentInfo(const QList<Component *> components) con
QDomElement root = doc.createElement(QLatin1String("updates"));
doc.appendChild(root);
- foreach (Component *component, components) {
+ foreach (const Component *component, components) {
QDomElement update = doc.createElement(QLatin1String("update"));
update.setAttribute(QLatin1String("name"), component->value(scDisplayName));
update.setAttribute(QLatin1String("version"), component->value(scVersion));
diff --git a/src/libs/installer/metadatajob.cpp b/src/libs/installer/metadatajob.cpp
index 7a6866dc2..68a242ebc 100644
--- a/src/libs/installer/metadatajob.cpp
+++ b/src/libs/installer/metadatajob.cpp
@@ -180,10 +180,6 @@ void MetadataJob::doStart()
item.insert(TaskRole::Authenticator, QVariant::fromValue(authenticator));
items.append(item);
}
- else {
- qCWarning(QInstaller::lcInstallerInstallLog) << "Trying to parse compressed repo as "
- "normal repository. Check repository syntax.";
- }
}
}
if (items.count() > 0) {
@@ -238,7 +234,7 @@ void MetadataJob::startXMLTask(const QList<FileTaskItem> &items)
void MetadataJob::doCancel()
{
reset();
- emitFinishedWithError(Job::Canceled, tr("Meta data download canceled."));
+ emitFinishedWithError(Job::Canceled, tr("Metadata download canceled."));
}
void MetadataJob::startUnzipRepositoryTask(const Repository &repo)
diff --git a/src/libs/installer/packagemanagercore.cpp b/src/libs/installer/packagemanagercore.cpp
index 145eb30d7..232024f66 100644
--- a/src/libs/installer/packagemanagercore.cpp
+++ b/src/libs/installer/packagemanagercore.cpp
@@ -764,6 +764,7 @@ int PackageManagerCore::downloadNeededArchives(double partProgressSize)
Q_ASSERT(partProgressSize >= 0 && partProgressSize <= 1);
QList<QPair<QString, QString> > archivesToDownload;
+ quint64 archivesToDownloadTotalSize = 0;
QList<Component*> neededComponents = orderedComponentsToInstall();
foreach (Component *component, neededComponents) {
// collect all archives to be downloaded
@@ -773,6 +774,7 @@ int PackageManagerCore::downloadNeededArchives(double partProgressSize)
.arg(component->name(), versionFreeString), QString::fromLatin1("%1/%2/%3")
.arg(component->repositoryUrl().toString(), component->name(), versionFreeString)));
}
+ archivesToDownloadTotalSize += component->value(scCompressedSize).toULongLong();
}
if (archivesToDownload.isEmpty())
@@ -783,6 +785,7 @@ int PackageManagerCore::downloadNeededArchives(double partProgressSize)
DownloadArchivesJob archivesJob(this);
archivesJob.setAutoDelete(false);
archivesJob.setArchivesToDownload(archivesToDownload);
+ archivesJob.setExpectedTotalSize(archivesToDownloadTotalSize);
connect(this, &PackageManagerCore::installationInterrupted, &archivesJob, &Job::cancel);
connect(&archivesJob, &DownloadArchivesJob::outputTextChanged,
ProgressCoordinator::instance(), &ProgressCoordinator::emitLabelAndDetailTextChanged);
@@ -847,7 +850,7 @@ void PackageManagerCore::setNeedsHardRestart(bool needsHardRestart)
*/
void PackageManagerCore::rollBackInstallation()
{
- emit titleMessageChanged(tr("Cancelling the Installer"));
+ emit titleMessageChanged(tr("Canceling the Installer"));
// this unregisters all operation progressChanged connected
ProgressCoordinator::instance()->setUndoMode();
@@ -1477,20 +1480,16 @@ bool PackageManagerCore::fetchCompressedPackagesTree()
if (!isInstaller() && status() == Failure)
return false;
- if (!d->fetchMetaInformationFromCompressedRepositories())
+ if (!d->fetchMetaInformationFromRepositories(DownloadType::CompressedPackage))
return false;
if (!d->addUpdateResourcesFromRepositories(true, true)) {
return false;
}
- PackagesList packages;
- const PackagesList &compPackages = d->compressedPackages();
- if (compPackages.isEmpty())
+ const PackagesList &packages = d->remotePackages();
+ if (packages.isEmpty())
return false;
- packages.append(compPackages);
- const PackagesList &rPackages = d->remotePackages();
- packages.append(rPackages);
return fetchPackagesTree(packages, installedPackages);
}
@@ -1520,7 +1519,7 @@ bool PackageManagerCore::fetchRemotePackagesTree()
if (!d->fetchMetaInformationFromRepositories())
return false;
- if (!d->fetchMetaInformationFromCompressedRepositories())
+ if (!d->fetchMetaInformationFromRepositories(DownloadType::CompressedPackage))
return false;
if (!d->addUpdateResourcesFromRepositories(true))
@@ -1556,9 +1555,8 @@ bool PackageManagerCore::fetchPackagesTree(const PackagesList &packages, const L
continue;
const LocalPackage localPackage = installedPackages.value(name);
- const QString updateVersion = update->data(scVersion).toString();
- if (KDUpdater::compareVersion(updateVersion, localPackage.version) <= 0)
- continue; // remote version equals or is less than the installed maintenance tool
+ if (!d->packageNeedsUpdate(localPackage, update))
+ continue;
const QDate updateDate = update->data(scReleaseDate).toDate();
if (localPackage.lastUpdateDate >= updateDate)
@@ -2192,26 +2190,50 @@ ComponentModel *PackageManagerCore::updaterComponentModel() const
/*!
Lists available packages filtered with \a regexp without GUI. Virtual
- components are not listed unless set visible.
+ components are not listed unless set visible. Optionally, a \a filters
+ hash containing package information elements and regular expressions
+ can be used to further filter listed packages.
\sa setVirtualComponentsVisible()
*/
-void PackageManagerCore::listAvailablePackages(const QString &regexp)
+void PackageManagerCore::listAvailablePackages(const QString &regexp, const QHash<QString, QString> &filters)
{
+ setPackageViewer();
qCDebug(QInstaller::lcInstallerInstallLog)
<< "Searching packages with regular expression:" << regexp;
+
+ ComponentModel *model = defaultComponentModel();
d->fetchMetaInformationFromRepositories(DownloadType::UpdatesXML);
d->addUpdateResourcesFromRepositories(true);
QRegularExpression re(regexp);
const PackagesList &packages = d->remotePackages();
+ if (!fetchAllPackages(packages, LocalPackagesHash())) {
+ qCWarning(QInstaller::lcInstallerInstallLog)
+ << "There was a problem with loading the package data.";
+ return;
+ }
PackagesList matchedPackages;
foreach (Package *package, packages) {
const QString name = package->data(scName).toString();
- if (re.match(name).hasMatch() &&
- (virtualComponentsVisible() ? true : !package->data(scVirtual, false).toBool())) {
- matchedPackages.append(package);
+ Component *component = componentByName(name);
+ if (!component)
+ continue;
+
+ const QModelIndex &idx = model->indexFromComponentName(component->treeName());
+ if (idx.isValid() && re.match(name).hasMatch()) {
+ bool ignoreComponent = false;
+ for (auto &key : filters.keys()) {
+ const QString elementValue = component->value(key);
+ QRegularExpression elementRegexp(filters.value(key));
+ if (elementValue.isEmpty() || !elementRegexp.match(elementValue).hasMatch()) {
+ ignoreComponent = true;
+ break;
+ }
+ }
+ if (!ignoreComponent)
+ matchedPackages.append(package);
}
}
if (matchedPackages.count() == 0)
@@ -2279,7 +2301,7 @@ bool PackageManagerCore::checkComponentsForInstallation(const QStringList &compo
errorMessage.append(tr("Cannot install component %1. Component is installed only as automatic "
"dependency to %2.\n").arg(name, component->autoDependencies().join(QLatin1Char(','))));
} else if (!component->isCheckable()) {
- errorMessage.append(tr("Cannot install component %1. Component is not checkable meaning you "
+ errorMessage.append(tr("Cannot install component %1. Component is not checkable, meaning you "
"have to select one of the subcomponents.\n").arg(name));
}
} else if (component->isInstalled()) {
@@ -2288,10 +2310,26 @@ bool PackageManagerCore::checkComponentsForInstallation(const QStringList &compo
model->setData(idx, Qt::Checked, Qt::CheckStateRole);
installComponentsFound = true;
}
- } else { // idx is invalid and component valid when we have invisible virtual component
- component->isVirtual()
- ? errorMessage.append(tr("Cannot install %1. Component is virtual.\n").arg(name))
- : errorMessage.append(tr("Cannot install %1. Component not found.\n").arg(name));
+ } else {
+ auto isDescendantOfVirtual = [&]() {
+ Component *trace = component;
+ forever {
+ trace = trace->parentComponent();
+ if (!trace) {
+ // We already checked the root component if there is no parent
+ return false;
+ } else if (trace->isVirtual()) {
+ errorMessage.append(tr("Cannot install %1. Component is a descendant "
+ "of a virtual component %2.\n").arg(name, trace->name()));
+ return true;
+ }
+ }
+ };
+ // idx is invalid and component valid when we have invisible virtual component
+ if (component->isVirtual())
+ errorMessage.append(tr("Cannot install %1. Component is virtual.\n").arg(name));
+ else if (!isDescendantOfVirtual())
+ errorMessage.append(tr("Cannot install %1. Component not found.\n").arg(name));
}
}
if (!installComponentsFound)
@@ -2305,6 +2343,7 @@ bool PackageManagerCore::checkComponentsForInstallation(const QStringList &compo
*/
void PackageManagerCore::listInstalledPackages(const QString &regexp)
{
+ setPackageViewer();
LocalPackagesHash installedPackages = this->localInstalledPackages();
if (!regexp.isEmpty()) {
@@ -2342,6 +2381,7 @@ PackageManagerCore::Status PackageManagerCore::updateComponentsSilently(const QS
if (componentList.count() == 0) {
qCDebug(QInstaller::lcInstallerInstallLog) << "No updates available.";
+ setCanceled();
} else {
// Check if essential components are available (essential components are disabled).
// If essential components are found, update first essential updates,
@@ -2703,21 +2743,21 @@ bool PackageManagerCore::checkAvailableSpace(QString &message) const
if (tempOnSameVolume && (installVolumeAvailableSize <= (required + tempRequired))) {
message = tr("Not enough disk space to store temporary files and the "
- "installation. %1 are available, while %2 are at least required.").arg(
+ "installation. %1 are available, while the minimum required is %2.").arg(
humanReadableSize(installVolumeAvailableSize), humanReadableSize(required + tempRequired));
return false;
}
if (installVolumeAvailableSize < required) {
message = tr("Not enough disk space to store all selected components! %1 are "
- "available while %2 are at least required.").arg(humanReadableSize(installVolumeAvailableSize),
+ "available, while the minimum required is %2.").arg(humanReadableSize(installVolumeAvailableSize),
humanReadableSize(required));
return false;
}
if (tempVolumeAvailableSize < tempRequired) {
- message = tr("Not enough disk space to store temporary files! %1 are available "
- "while %2 are at least required.").arg(humanReadableSize(tempVolumeAvailableSize),
+ message = tr("Not enough disk space to store temporary files! %1 are available, "
+ "while the minimum required is %2.").arg(humanReadableSize(tempVolumeAvailableSize),
humanReadableSize(tempRequired));
return false;
}
@@ -3402,11 +3442,11 @@ bool PackageManagerCore::isPackageManager() const
}
/*!
- Sets current installer to be offline generator based on \a offlineGenerator.
+ Sets current installer to be offline generator.
*/
-void PackageManagerCore::setOfflineGenerator(bool offlineGenerator)
+void PackageManagerCore::setOfflineGenerator()
{
- d->m_offlineGenerator = offlineGenerator;
+ d->m_magicMarkerSupplement = BinaryContent::OfflineGenerator;
}
/*!
@@ -3420,6 +3460,24 @@ bool PackageManagerCore::isOfflineGenerator() const
}
/*!
+ Sets the current installer as the package viewer.
+*/
+void PackageManagerCore::setPackageViewer()
+{
+ d->m_magicMarkerSupplement = BinaryContent::PackageViewer;
+}
+
+/*!
+ Returns \c true if the current installer is executed as package viewer.
+
+ \sa {installer::isPackageViewer}{installer.isPackageViewer}
+*/
+bool PackageManagerCore::isPackageViewer() const
+{
+ return d->isPackageViewer();
+}
+
+/*!
Sets the installer magic binary marker based on \a magicMarker and
userSetBinaryMarker to \c true.
*/
@@ -3660,7 +3718,7 @@ void PackageManagerCore::storeReplacedComponents(QHash<QString, Component *> &co
qCWarning(QInstaller::lcDeveloperBuild) << componentName << "- Does not exist in the repositories anymore.";
continue;
}
- if (!componentToReplace && !d->componentsToReplace().contains(componentName)) {
+ if (!d->componentsToReplace().contains(componentName)) {
componentToReplace = new Component(this);
componentToReplace->setValue(scName, componentName);
} else {
@@ -3799,10 +3857,8 @@ bool PackageManagerCore::fetchUpdaterPackages(const PackagesList &remotes, const
continue; // Update for not installed package found, skip it.
const LocalPackage &localPackage = locals.value(name);
- const QString updateVersion = update->data(scVersion).toString();
- if (KDUpdater::compareVersion(updateVersion, localPackage.version) <= 0)
+ if (!d->packageNeedsUpdate(localPackage, update))
continue;
-
// It is quite possible that we may have already installed the update. Lets check the last
// update date of the package and the release date of the update. This way we can compare and
// figure out if the update has been installed or not.
@@ -3929,7 +3985,7 @@ void PackageManagerCore::updateDisplayVersions(const QString &displayKey)
const QString displayVersionRemote = findDisplayVersion(key, componentsHash,
scVersion, visited);
if (displayVersionRemote.isEmpty())
- componentsHash.value(key)->setValue(displayKey, tr("invalid"));
+ componentsHash.value(key)->setValue(displayKey, tr("Invalid"));
else
componentsHash.value(key)->setValue(displayKey, displayVersionRemote);
}
diff --git a/src/libs/installer/packagemanagercore.h b/src/libs/installer/packagemanagercore.h
index d4833a979..b5ef6304e 100644
--- a/src/libs/installer/packagemanagercore.h
+++ b/src/libs/installer/packagemanagercore.h
@@ -33,6 +33,7 @@
#include "repository.h"
#include "qinstallerglobal.h"
#include "utils.h"
+#include "commandlineparser.h"
#include <QtCore/QHash>
#include <QtCore/QObject>
@@ -242,7 +243,8 @@ public:
ComponentModel *defaultComponentModel() const;
ComponentModel *updaterComponentModel() const;
void listInstalledPackages(const QString &regexp = QString());
- void listAvailablePackages(const QString &regexp);
+ void listAvailablePackages(const QString &regexp = QString(),
+ const QHash<QString, QString> &filters = QHash<QString, QString>());
PackageManagerCore::Status updateComponentsSilently(const QStringList &componentsToUpdate);
PackageManagerCore::Status installSelectedComponentsSilently(const QStringList& components);
PackageManagerCore::Status installDefaultComponentsSilently();
@@ -264,9 +266,12 @@ public:
Q_INVOKABLE void setPackageManager();
Q_INVOKABLE bool isPackageManager() const;
- void setOfflineGenerator(bool offlineGenerator = true);
+ void setOfflineGenerator();
Q_INVOKABLE bool isOfflineGenerator() const;
+ void setPackageViewer();
+ Q_INVOKABLE bool isPackageViewer() const;
+
void setUserSetBinaryMarker(qint64 magicMarker);
Q_INVOKABLE bool isUserSetBinaryMarker() const;
diff --git a/src/libs/installer/packagemanagercore_p.cpp b/src/libs/installer/packagemanagercore_p.cpp
index 270cd7760..51c044356 100644
--- a/src/libs/installer/packagemanagercore_p.cpp
+++ b/src/libs/installer/packagemanagercore_p.cpp
@@ -211,7 +211,6 @@ static void deferredRename(const QString &oldName, const QString &newName, bool
PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core)
: m_updateFinder(nullptr)
- , m_compressedFinder(nullptr)
, m_localPackageHub(std::make_shared<LocalPackageHub>())
, m_status(PackageManagerCore::Unfinished)
, m_needsHardRestart(false)
@@ -225,6 +224,7 @@ PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core)
, m_repoFetched(false)
, m_updateSourcesAdded(false)
, m_magicBinaryMarker(0) // initialize with pseudo marker
+ , m_magicMarkerSupplement(BinaryContent::Default)
, m_componentsToInstallCalculated(false)
, m_componentScriptEngine(nullptr)
, m_controlScriptEngine(nullptr)
@@ -243,14 +243,12 @@ PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core)
, m_autoAcceptLicenses(false)
, m_disableWriteMaintenanceTool(false)
, m_autoConfirmCommand(false)
- , m_offlineGenerator(false)
{
}
PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core, qint64 magicInstallerMaker,
const QList<OperationBlob> &performedOperations)
: m_updateFinder(nullptr)
- , m_compressedFinder(nullptr)
, m_localPackageHub(std::make_shared<LocalPackageHub>())
, m_status(PackageManagerCore::Unfinished)
, m_needsHardRestart(false)
@@ -264,6 +262,7 @@ PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core, q
, m_repoFetched(false)
, m_updateSourcesAdded(false)
, m_magicBinaryMarker(magicInstallerMaker)
+ , m_magicMarkerSupplement(BinaryContent::Default)
, m_componentsToInstallCalculated(false)
, m_componentScriptEngine(nullptr)
, m_controlScriptEngine(nullptr)
@@ -282,7 +281,6 @@ PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core, q
, m_autoAcceptLicenses(false)
, m_disableWriteMaintenanceTool(false)
, m_autoConfirmCommand(false)
- , m_offlineGenerator(false)
{
foreach (const OperationBlob &operation, performedOperations) {
QScopedPointer<QInstaller::Operation> op(KDUpdater::UpdateOperationFactory::instance()
@@ -717,7 +715,12 @@ bool PackageManagerCorePrivate::isPackageManager() const
bool PackageManagerCorePrivate::isOfflineGenerator() const
{
- return m_offlineGenerator;
+ return m_magicMarkerSupplement == BinaryContent::OfflineGenerator;
+}
+
+bool PackageManagerCorePrivate::isPackageViewer() const
+{
+ return m_magicMarkerSupplement == BinaryContent::PackageViewer;
}
bool PackageManagerCorePrivate::statusCanceledOrFailed() const
@@ -2017,7 +2020,7 @@ bool PackageManagerCorePrivate::runUninstaller()
m_core->dropAdminRights();
ProgressCoordinator::instance()->emitLabelAndDetailTextChanged(QString::fromLatin1("\n%1").arg(
- success ? tr("Uninstallation completed successfully.") : tr("Uninstallation aborted.")));
+ success ? tr("Removal completed successfully.") : tr("Removal aborted.")));
emit uninstallationFinished();
return success;
@@ -2251,7 +2254,8 @@ void PackageManagerCorePrivate::installComponent(Component *component, double pr
component->value(scUncompressedSize).toULongLong(),
component->value(scInheritVersion),
component->isCheckable(),
- component->isExpandedByDefault());
+ component->isExpandedByDefault(),
+ component->value(scContentSha1));
m_localPackageHub->writeToDisk();
component->setInstalled();
@@ -2308,7 +2312,7 @@ void PackageManagerCorePrivate::deleteMaintenanceTool()
QLatin1String("uninstall.vbs")).absoluteFilePath());
QFile f(batchfile);
if (!f.open(QIODevice::WriteOnly | QIODevice::Text))
- throw Error(tr("Cannot prepare uninstall"));
+ throw Error(tr("Cannot prepare removal"));
QTextStream batch(&f);
batch << "Set fso = WScript.CreateObject(\"Scripting.FileSystemObject\")\n";
@@ -2339,7 +2343,7 @@ void PackageManagerCorePrivate::deleteMaintenanceTool()
}
if (!QProcessWrapper::startDetached(QLatin1String("cscript"), arguments, QDir::rootPath()))
- throw Error(tr("Cannot start uninstall"));
+ throw Error(tr("Cannot start removal"));
#else
// every other platform has no problem if we just delete ourselves now
QFile maintenanceTool(QFileInfo(installerBinaryPath()).absoluteFilePath());
@@ -2437,7 +2441,7 @@ void PackageManagerCorePrivate::runUndoOperations(const OperationList &undoOpera
const QMessageBox::StandardButton button =
MessageBoxHandler::warning(MessageBoxHandler::currentBestSuitParent(),
QLatin1String("installationErrorWithIgnore"), tr("Installer Error"),
- tr("Error during uninstallation process:\n%1").arg(undoOperation->errorString()),
+ tr("Error during removal process:\n%1").arg(undoOperation->errorString()),
QMessageBox::Retry | QMessageBox::Ignore, QMessageBox::Ignore);
if (button == QMessageBox::Retry)
@@ -2480,7 +2484,7 @@ PackagesList PackageManagerCorePrivate::remotePackages()
m_updateFinder = new KDUpdater::UpdateFinder;
m_updateFinder->setAutoDelete(false);
- m_updateFinder->setPackageSources(m_packageSources);
+ m_updateFinder->setPackageSources(m_packageSources + m_compressedPackageSources);
m_updateFinder->setLocalPackageHub(m_localPackageHub);
m_updateFinder->run();
@@ -2494,29 +2498,6 @@ PackagesList PackageManagerCorePrivate::remotePackages()
return m_updateFinder->updates();
}
-PackagesList PackageManagerCorePrivate::compressedPackages()
-{
- if (m_compressedUpdates && m_compressedFinder)
- return m_compressedFinder->updates();
- m_compressedUpdates = false;
- delete m_compressedFinder;
-
- m_compressedFinder = new KDUpdater::UpdateFinder;
- m_compressedFinder->setAutoDelete(false);
- m_compressedFinder->addCompressedPackage(true);
- m_compressedFinder->setPackageSources(m_compressedPackageSources);
-
- m_compressedFinder->setLocalPackageHub(m_localPackageHub);
- m_compressedFinder->run();
- if (m_compressedFinder->updates().isEmpty()) {
- setStatus(PackageManagerCore::Failure, tr("Cannot retrieve remote tree %1.")
- .arg(m_compressedFinder->errorString()));
- return PackagesList();
- }
- m_compressedUpdates = true;
- return m_compressedFinder->updates();
-}
-
/*!
Returns a hash containing the installed package name and it's associated package information. If
the application is running in installer mode or the local components file could not be parsed, the
@@ -2584,42 +2565,6 @@ bool PackageManagerCorePrivate::fetchMetaInformationFromRepositories(DownloadTyp
return m_repoFetched;
}
-bool PackageManagerCorePrivate::fetchMetaInformationFromCompressedRepositories()
-{
- bool compressedRepoFetched = false;
-
- m_compressedUpdates = false;
- m_updateSourcesAdded = false;
-
- try {
- //Tell MetadataJob that only compressed packages needed to be fetched and not all.
- //We cannot do this in general fetch meta method as the compressed packages might be
- //installed after components tree is generated
- m_metadataJob.addDownloadType(DownloadType::CompressedPackage);
- m_metadataJob.start();
- m_metadataJob.waitForFinished();
- } catch (Error &error) {
- setStatus(PackageManagerCore::Failure, tr("Cannot retrieve meta information: %1")
- .arg(error.message()));
- return compressedRepoFetched;
- }
-
- if (m_metadataJob.error() != Job::NoError) {
- switch (m_metadataJob.error()) {
- case QInstaller::UserIgnoreError:
- break; // we can simply ignore this error, the user knows about it
- default:
- //Do not change core status here, we can recover if there is invalid
- //compressed repository
- setStatus(m_core->status(), m_metadataJob.errorString());
- return compressedRepoFetched;
- }
- }
-
- compressedRepoFetched = true;
- return compressedRepoFetched;
-}
-
bool PackageManagerCorePrivate::addUpdateResourcesFromRepositories(bool parseChecksum, bool compressedRepository)
{
if (!compressedRepository && m_updateSourcesAdded)
@@ -2679,8 +2624,8 @@ bool PackageManagerCorePrivate::addUpdateResourcesFromRepositories(bool parseChe
if (!checksum.isNull())
m_core->setTestChecksum(checksum.toElement().text().toLower() == scTrue);
}
- if (compressedRepository)
- m_compressedPackageSources.insert(PackageSource(QUrl::fromLocalFile(data.directory), 1));
+ if (data.repository.isCompressed())
+ m_compressedPackageSources.insert(PackageSource(QUrl::fromLocalFile(data.directory), 2));
else
m_packageSources.insert(PackageSource(QUrl::fromLocalFile(data.directory), 1));
@@ -2913,4 +2858,19 @@ bool PackageManagerCorePrivate::askUserConfirmCommand() const
}
}
+bool PackageManagerCorePrivate::packageNeedsUpdate(const LocalPackage &localPackage, const Package *update) const
+{
+ bool updateNeeded = true;
+ const QString contentSha1 = update->data(scContentSha1).toString();
+ if (!contentSha1.isEmpty()) {
+ if (contentSha1 == localPackage.contentSha1)
+ updateNeeded = false;
+ } else {
+ const QString updateVersion = update->data(scVersion).toString();
+ if (KDUpdater::compareVersion(updateVersion, localPackage.version) <= 0)
+ updateNeeded = false;
+ }
+ return updateNeeded;
+}
+
} // namespace QInstaller
diff --git a/src/libs/installer/packagemanagercore_p.h b/src/libs/installer/packagemanagercore_p.h
index 858baf9eb..65f0e43eb 100644
--- a/src/libs/installer/packagemanagercore_p.h
+++ b/src/libs/installer/packagemanagercore_p.h
@@ -132,6 +132,8 @@ public:
bool runOfflineGenerator();
bool isOfflineGenerator() const;
+ bool isPackageViewer() const;
+
QString replaceVariables(const QString &str) const;
QByteArray replaceVariables(const QByteArray &str) const;
@@ -175,7 +177,6 @@ signals:
public:
UpdateFinder *m_updateFinder;
- UpdateFinder *m_compressedFinder;
QSet<PackageSource> m_packageSources;
QSet<PackageSource> m_compressedPackageSources;
std::shared_ptr<LocalPackageHub> m_localPackageHub;
@@ -242,10 +243,8 @@ private:
bool adminRightsGained, bool deleteOperation);
PackagesList remotePackages();
- PackagesList compressedPackages();
LocalPackagesHash localInstalledPackages();
bool fetchMetaInformationFromRepositories(DownloadType type = DownloadType::All);
- bool fetchMetaInformationFromCompressedRepositories();
bool addUpdateResourcesFromRepositories(bool parseChecksum, bool compressedRepository = false);
void processFilesForDelayedDeletion();
void findExecutablesRecursive(const QString &path, const QStringList &excludeFiles, QStringList *result);
@@ -254,19 +253,20 @@ private:
bool acceptLicenseAgreements() const;
bool askUserAcceptLicense(const QString &name, const QString &content) const;
bool askUserConfirmCommand() const;
+ bool packageNeedsUpdate(const LocalPackage &localPackage, const Package *update) const;
private:
PackageManagerCore *m_core;
MetadataJob m_metadataJob;
bool m_updates;
- bool m_compressedUpdates;
bool m_repoFetched;
bool m_updateSourcesAdded;
qint64 m_magicBinaryMarker;
+ int m_magicMarkerSupplement;
+
bool m_componentsToInstallCalculated;
- bool m_foundEssentialUpdate;
- bool m_offlineGenerator;
+ bool m_foundEssentialUpdate;;
mutable ScriptEngine *m_componentScriptEngine;
mutable ScriptEngine *m_controlScriptEngine;
diff --git a/src/libs/installer/packagemanagergui.cpp b/src/libs/installer/packagemanagergui.cpp
index 52b0bb222..67a2123af 100644
--- a/src/libs/installer/packagemanagergui.cpp
+++ b/src/libs/installer/packagemanagergui.cpp
@@ -321,7 +321,7 @@ PackageManagerGui::PackageManagerGui(PackageManagerCore *core, QWidget *parent)
QFile sheet(styleSheetFile);
if (sheet.exists()) {
if (sheet.open(QIODevice::ReadOnly)) {
- setStyleSheet(QString::fromLatin1(sheet.readAll()));
+ qApp->setStyleSheet(QString::fromLatin1(sheet.readAll()));
} else {
qCWarning(QInstaller::lcDeveloperBuild) << "The specified style sheet file "
"can not be opened.";
@@ -945,7 +945,7 @@ void PackageManagerGui::cancelButtonClicked()
interrupt = true;
question = tr("Do you want to cancel the installation process?");
if (m_core->isUninstaller())
- question = tr("Do you want to cancel the uninstallation process?");
+ question = tr("Do you want to cancel the removal process?");
} else {
question = tr("Do you want to quit the installer application?");
if (m_core->isUninstaller())
@@ -1621,6 +1621,10 @@ bool IntroductionPage::validatePage()
error = QLatin1String("<font color=\"red\">") + error + tr(" Only local package "
"management available.") + QLatin1String("</font>");
}
+ } else if (core->status() == PackageManagerCore::ForceUpdate) {
+ // replaces the error string from packagemanagercore
+ error = tr("There is an important update available. Please select '%1' first")
+ .arg(m_updateComponents->text().remove(QLatin1Char('&')));
}
setErrorMessage(error);
}
@@ -1959,7 +1963,7 @@ LicenseAgreementPage::LicenseAgreementPage(PackageManagerCore *core)
layout->addWidget(licenseSplitter);
m_acceptCheckBox = new QCheckBox(this);
- m_acceptCheckBox->setShortcut(QKeySequence(tr("Alt+A", "agree license")));
+ m_acceptCheckBox->setShortcut(QKeySequence(tr("Alt+A", "Agree license")));
m_acceptCheckBox->setObjectName(QLatin1String("AcceptLicenseCheckBox"));
ClickForwarder *acceptClickForwarder = new ClickForwarder(m_acceptCheckBox);
@@ -2312,7 +2316,7 @@ TargetDirectoryPage::TargetDirectoryPage(PackageManagerCore *core)
QPushButton *browseButton = new QPushButton(this);
browseButton->setObjectName(QLatin1String("BrowseDirectoryButton"));
connect(browseButton, &QAbstractButton::clicked, this, &TargetDirectoryPage::dirRequested);
- browseButton->setShortcut(QKeySequence(tr("Alt+R", "browse file system to choose a file")));
+ browseButton->setShortcut(QKeySequence(tr("Alt+R", "Browse file system to choose a file")));
browseButton->setText(tr("B&rowse..."));
browseButton->setToolTip(TargetDirectoryPage::tr("Browse file system to choose the installation directory."));
hlayout->addWidget(browseButton);
diff --git a/src/libs/installer/performinstallationform.cpp b/src/libs/installer/performinstallationform.cpp
index 2fb6026cc..a61c0d88b 100644
--- a/src/libs/installer/performinstallationform.cpp
+++ b/src/libs/installer/performinstallationform.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2020 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -80,6 +80,7 @@ PerformInstallationForm::PerformInstallationForm(QObject *parent)
: QObject(parent)
, m_progressBar(nullptr)
, m_progressLabel(nullptr)
+ , m_downloadStatus(nullptr)
, m_productImagesScrollArea(nullptr)
, m_productImagesLabel(nullptr)
, m_detailsButton(nullptr)
@@ -120,6 +121,8 @@ void PerformInstallationForm::setupUi(QWidget *widget)
m_downloadStatus = new QLabel(widget);
m_downloadStatus->setObjectName(QLatin1String("DownloadStatus"));
m_downloadStatus->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);
+ m_downloadStatus->setWordWrap(true);
+ m_downloadStatus->setTextFormat(Qt::TextFormat::RichText);
topLayout->addWidget(m_downloadStatus);
connect(ProgressCoordinator::instance(), &ProgressCoordinator::downloadStatusChanged, this,
&PerformInstallationForm::onDownloadStatusChanged);
@@ -281,8 +284,7 @@ bool PerformInstallationForm::isShowingDetails() const
*/
void PerformInstallationForm::onDownloadStatusChanged(const QString &status)
{
- m_downloadStatus->setText(m_downloadStatus->fontMetrics().elidedText(status, Qt::ElideRight,
- m_downloadStatus->width()));
+ m_downloadStatus->setText(status);
}
/*!
diff --git a/src/libs/installer/qsettingswrapper.cpp b/src/libs/installer/qsettingswrapper.cpp
index 56db28d78..f57750bc1 100644
--- a/src/libs/installer/qsettingswrapper.cpp
+++ b/src/libs/installer/qsettingswrapper.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -74,9 +74,9 @@ public:
Private(const QString &fileName, QSettings::Format format)
: m_filename(fileName)
+ , m_format(format)
, settings(fileName, format)
{
- m_format = format;
m_scope = settings.scope();
m_application = settings.applicationName();
m_organization = settings.organizationName();
diff --git a/src/libs/installer/remoteclient_p.h b/src/libs/installer/remoteclient_p.h
index ba60bc7ac..9cc679de8 100644
--- a/src/libs/installer/remoteclient_p.h
+++ b/src/libs/installer/remoteclient_p.h
@@ -133,8 +133,8 @@ public:
QCoreApplication::translate("RemoteClient", "Cannot get authorization."),
QCoreApplication::translate("RemoteClient",
"Cannot get authorization that is needed for continuing the installation.\n\n"
- "Please start the setup program as a user with the appropriate rights.\n"
- "Or accept the elevation of access rights if being asked."),
+ "Please start the setup program as a user with the appropriate rights,\n"
+ "or accept the elevation of access rights if being asked."),
QMessageBox::Abort | QMessageBox::Retry, QMessageBox::Abort);
if (res == QMessageBox::Retry)
started = AdminAuthorization::execute(0, m_serverCommand, m_serverArguments);
diff --git a/src/libs/installer/selfrestartoperation.cpp b/src/libs/installer/selfrestartoperation.cpp
index 8e53b8201..360dc60b2 100644
--- a/src/libs/installer/selfrestartoperation.cpp
+++ b/src/libs/installer/selfrestartoperation.cpp
@@ -61,7 +61,7 @@ bool SelfRestartOperation::performOperation()
if (!core->isMaintainer()) {
setError(UserDefinedError);
- setErrorString(tr("Self Restart: Only valid within updater or packagemanager mode."));
+ setErrorString(tr("Self Restart: Only valid within updater or package manager mode."));
return false;
}
diff --git a/src/libs/installer/settingsoperation.cpp b/src/libs/installer/settingsoperation.cpp
index 95ba5266d..c5fe8384c 100644
--- a/src/libs/installer/settingsoperation.cpp
+++ b/src/libs/installer/settingsoperation.cpp
@@ -82,7 +82,7 @@ bool SettingsOperation::checkArguments()
if (!possibleMethodValues.contains(method)) {
setError(InvalidArguments);
setErrorString(tr("Current method argument calling \"%1\" with arguments \"%2\" is not "
- "supported. Please use set, remove, add_array_value or remove_array_value.").arg(name(),
+ "supported. Please use set, remove, add_array_value, or remove_array_value.").arg(name(),
arguments().join(QLatin1String("; "))));
return false;
}
diff --git a/src/libs/installer/utils.cpp b/src/libs/installer/utils.cpp
index 59be2171b..7506a13fe 100644
--- a/src/libs/installer/utils.cpp
+++ b/src/libs/installer/utils.cpp
@@ -351,12 +351,12 @@ static QString qt_create_commandline(const QString &program, const QStringList &
// as escaping the quote -- rather put the \ behind the quote: e.g.
// rather use "foo"\ than "foo\"
QString endQuote(QLatin1Char('\"'));
- int i = tmp.length();
- while (i > 0 && tmp.at(i - 1) == QLatin1Char('\\')) {
- --i;
+ int j = tmp.length();
+ while (j > 0 && tmp.at(j - 1) == QLatin1Char('\\')) {
+ --j;
endQuote += QLatin1Char('\\');
}
- args += QLatin1String(" \"") + tmp.left(i) + endQuote;
+ args += QLatin1String(" \"") + tmp.left(j) + endQuote;
} else {
args += QLatin1Char(' ') + tmp;
}