summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKatja Marttila <katja.marttila@qt.io>2022-03-25 15:38:50 +0200
committerKatja Marttila <katja.marttila@qt.io>2022-04-28 15:18:34 +0300
commita28cf55b5a5007c0dd952b3012c076d9da329f0f (patch)
treeaba86d92da394969acfcf2eb6d7b7578c9432c36 /src
parent23ec1e91f4e0c567f5953de149b2ab3496490e87 (diff)
Speed up component selection in component selection pages
If a lot of components are installed, maintenancetool was slow to select/unselect a single component. This was caused because the whole tree's components were recalculated. Fixed so that only the selected/unselected components and their dependencies and autodependencies are recalculated instead of whole tree. This change speeds up clicking tree item from zero to 90 percent, depending on how much components are already installed. The more components are installed as autodependency, the slower it gets to select the items. Task-number: QTIFW-2522 Change-Id: I5e824aed8787fd7ecdce72b15a1b13848f0a3923 Reviewed-by: Arttu Tarkiainen <arttu.tarkiainen@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/libs/installer/componentmodel.cpp41
-rw-r--r--src/libs/installer/componentmodel.h8
-rw-r--r--src/libs/installer/componentselectionpage_p.cpp16
-rw-r--r--src/libs/installer/installercalculator.cpp232
-rw-r--r--src/libs/installer/installercalculator.h39
-rw-r--r--src/libs/installer/packagemanagercore.cpp87
-rw-r--r--src/libs/installer/packagemanagercore.h2
-rw-r--r--src/libs/installer/packagemanagercore_p.cpp73
-rw-r--r--src/libs/installer/packagemanagercore_p.h19
-rw-r--r--src/libs/installer/qinstallerglobal.cpp14
-rw-r--r--src/libs/installer/qinstallerglobal.h5
-rw-r--r--src/libs/installer/uninstallercalculator.cpp170
-rw-r--r--src/libs/installer/uninstallercalculator.h19
13 files changed, 491 insertions, 234 deletions
diff --git a/src/libs/installer/componentmodel.cpp b/src/libs/installer/componentmodel.cpp
index 88e502164..3bb9bc72e 100644
--- a/src/libs/installer/componentmodel.cpp
+++ b/src/libs/installer/componentmodel.cpp
@@ -58,14 +58,14 @@ namespace QInstaller {
*/
/*!
- \fn void QInstaller::ComponentModel::checkStateChanged(const QModelIndex &index)
+ \fn void QInstaller::ComponentModel::componentsCheckStateChanged(const QList<QModelIndex> &indexes)
- This signal is emitted whenever the checked state of a component is changed. The \a index value
- indicates the QModelIndex representation of the component as seen from the model.
+ This signal is emitted whenever the checked state of components are changed. The \a indexes value
+ indicates the QModelIndexes representation of the components as seen from the model.
*/
/*!
- \fn void QInstaller::ComponentModel::checkStateChanged(QInstaller::ComponentModel::ModelState state)
+ \fn void QInstaller::ComponentModel::modelCheckStateChanged(QInstaller::ComponentModel::ModelState state)
This signal is emitted whenever the checked state of a model is changed after all state
calculations have taken place. The \a state is a combination of \c ModelStateFlag values
@@ -238,7 +238,7 @@ QVariant ComponentModel::data(const QModelIndex &index, int role) const
/*!
Sets the \a role data for the item at \a index to \a value. Returns true if successful;
otherwise returns false. The dataChanged() signal is emitted if the data was successfully set.
- The checkStateChanged() signals are emitted in addition if the checked state of the item is set.
+ The componentsCheckStateChanged() signal is emitted in addition if the checked state of the item is set.
*/
bool ComponentModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
@@ -260,12 +260,13 @@ bool ComponentModel::setData(const QModelIndex &index, const QVariant &value, in
const Qt::CheckState oldValue = component->checkState();
newValue = (oldValue == Qt::Checked) ? Qt::Unchecked : Qt::Checked;
}
- QSet<QModelIndex> changed = updateCheckedState(nodes << component, newValue);
+ const QList<QModelIndex> changed = updateCheckedState(nodes << component, newValue);
foreach (const QModelIndex &changedIndex, changed) {
emit dataChanged(changedIndex, changedIndex);
- emit checkStateChanged(changedIndex);
}
- updateAndEmitModelState(); // update the internal state
+ updateModelState();
+ if (changed.count() > 0)
+ emit componentsCheckStateChanged(changed);
} else {
component->setData(value, role);
emit dataChanged(index, index);
@@ -425,12 +426,12 @@ void ComponentModel::reset(QList<Component *> rootComponents)
Sets the checked state of every component in the model to be \a state.
The ComponentModel::PartiallyChecked flag is ignored by this function. Note that components
- are not changed if they are not checkable. The dataChanged() and checkStateChanged() signals
+ are not changed if they are not checkable. The dataChanged() and componentsCheckStateChanged() signals
are emitted.
*/
void ComponentModel::setCheckedState(QInstaller::ComponentModel::ModelStateFlag state)
{
- QSet<QModelIndex> changed;
+ QList<QModelIndex> changed;
switch (state) {
case AllChecked:
changed = updateCheckedState(m_currentCheckedState[Qt::Unchecked], Qt::Checked);
@@ -453,9 +454,9 @@ void ComponentModel::setCheckedState(QInstaller::ComponentModel::ModelStateFlag
// notify about changes done to the model
foreach (const QModelIndex &index, changed) {
emit dataChanged(index, index);
- emit checkStateChanged(index);
}
- updateAndEmitModelState(); // update the internal state
+ updateModelState();
+ emit modelCheckStateChanged(m_modelState);
}
@@ -493,10 +494,11 @@ void ComponentModel::postModelReset()
}
m_currentCheckedState = m_initialCheckedState;
- updateAndEmitModelState(); // update the internal state
+ updateModelState(); // update the internal state
+ emit modelCheckStateChanged(m_modelState);
}
-void ComponentModel::updateAndEmitModelState()
+void ComponentModel::updateModelState()
{
m_modelState = ComponentModel::DefaultChecked;
if (m_initialCheckedState != m_currentCheckedState)
@@ -511,8 +513,6 @@ void ComponentModel::updateAndEmitModelState()
m_modelState |= ComponentModel::AllChecked;
m_modelState &= ~ComponentModel::PartiallyChecked;
}
-
- emit checkStateChanged(m_modelState);
}
void ComponentModel::collectComponents(Component *const component, const QModelIndex &parent) const
@@ -556,7 +556,7 @@ static Qt::CheckState verifyPartiallyChecked(Component *component)
} // namespace ComponentModelPrivate
-QSet<QModelIndex> ComponentModel::updateCheckedState(const ComponentSet &components, Qt::CheckState state)
+QList<QModelIndex> ComponentModel::updateCheckedState(const ComponentSet &components, const Qt::CheckState state)
{
// get all parent nodes for the components we're going to update
QMultiMap<QString, Component *> sortedNodesMap;
@@ -567,7 +567,7 @@ QSet<QModelIndex> ComponentModel::updateCheckedState(const ComponentSet &compone
}
}
- QSet<QModelIndex> changed;
+ QList<QModelIndex> changed;
const ComponentList sortedNodes = sortedNodesMap.values();
// we can start in descending order to check node and tri-state nodes properly
for (int i = sortedNodes.count(); i > 0; i--) {
@@ -589,7 +589,10 @@ QSet<QModelIndex> ComponentModel::updateCheckedState(const ComponentSet &compone
continue;
node->setCheckState(newState);
- changed.insert(indexFromComponentName(node->treeName()));
+ QModelIndex index = indexFromComponentName(node->treeName());
+ //Prepend to the list so that install order is correct (parent first)
+ if (!changed.contains(index))
+ changed.prepend(indexFromComponentName(node->treeName()));
m_currentCheckedState[Qt::Checked].remove(node);
m_currentCheckedState[Qt::Unchecked].remove(node);
diff --git a/src/libs/installer/componentmodel.h b/src/libs/installer/componentmodel.h
index 78d7e6401..f9fbae47a 100644
--- a/src/libs/installer/componentmodel.h
+++ b/src/libs/installer/componentmodel.h
@@ -90,17 +90,17 @@ public Q_SLOTS:
void setCheckedState(QInstaller::ComponentModel::ModelStateFlag state);
Q_SIGNALS:
- void checkStateChanged(const QModelIndex &index);
- void checkStateChanged(QInstaller::ComponentModel::ModelState state);
+ void componentsCheckStateChanged(const QList<QModelIndex> &indexes);
+ void modelCheckStateChanged(QInstaller::ComponentModel::ModelState state);
private Q_SLOTS:
void onVirtualStateChanged();
private:
void postModelReset();
- void updateAndEmitModelState();
+ void updateModelState();
void collectComponents(Component *const component, const QModelIndex &parent) const;
- QSet<QModelIndex> updateCheckedState(const ComponentSet &components, Qt::CheckState state);
+ QList<QModelIndex> updateCheckedState(const ComponentSet &components, const Qt::CheckState state);
private:
PackageManagerCore *m_core;
diff --git a/src/libs/installer/componentselectionpage_p.cpp b/src/libs/installer/componentselectionpage_p.cpp
index e775c0cb4..5e44d153c 100644
--- a/src/libs/installer/componentselectionpage_p.cpp
+++ b/src/libs/installer/componentselectionpage_p.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2021 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -185,10 +185,16 @@ ComponentSelectionPagePrivate::ComponentSelectionPagePrivate(ComponentSelectionP
m_stackedLayout->addWidget(progressStackedWidget);
m_stackedLayout->setCurrentIndex(0);
- connect(m_allModel, SIGNAL(checkStateChanged(QInstaller::ComponentModel::ModelState)), this,
- SLOT(onModelStateChanged(QInstaller::ComponentModel::ModelState)));
- connect(m_updaterModel, SIGNAL(checkStateChanged(QInstaller::ComponentModel::ModelState)),
- this, SLOT(onModelStateChanged(QInstaller::ComponentModel::ModelState)));
+ connect(m_allModel, &ComponentModel::modelCheckStateChanged,
+ this, &ComponentSelectionPagePrivate::onModelStateChanged);
+ connect(m_updaterModel, &ComponentModel::modelCheckStateChanged,
+ this, &ComponentSelectionPagePrivate::onModelStateChanged);
+
+ connect(m_allModel, &ComponentModel::componentsCheckStateChanged, this,
+ [=]() { onModelStateChanged(m_allModel->checkedState());});
+
+ connect(m_updaterModel, &ComponentModel::componentsCheckStateChanged, this,
+ [=]() { onModelStateChanged(m_allModel->checkedState());});
connect(m_core, SIGNAL(metaJobProgress(int)), this, SLOT(onProgressChanged(int)));
connect(m_core, SIGNAL(metaJobInfoMessage(QString)), this, SLOT(setMessage(QString)));
diff --git a/src/libs/installer/installercalculator.cpp b/src/libs/installer/installercalculator.cpp
index ba8bf9db3..307c0d2fb 100644
--- a/src/libs/installer/installercalculator.cpp
+++ b/src/libs/installer/installercalculator.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -33,8 +33,6 @@
#include "settings.h"
#include <globals.h>
-#include <QDebug>
-
namespace QInstaller {
/*!
@@ -43,34 +41,18 @@ namespace QInstaller {
\internal
*/
-InstallerCalculator::InstallerCalculator(const QList<Component *> &allComponents)
+InstallerCalculator::InstallerCalculator(const QList<Component *> &allComponents, const QHash<QString, QStringList> &autoDependencyComponentHash)
: m_allComponents(allComponents)
+ , m_autoDependencyComponentHash(autoDependencyComponentHash)
{
}
-void InstallerCalculator::insertInstallReason(Component *component,
- InstallReasonType installReason, const QString &referencedComponentName)
+InstallerCalculator::InstallReasonType InstallerCalculator::installReasonType(const Component *c) const
{
- // keep the first reason
- if (m_toInstallComponentIdReasonHash.contains(component->name()))
- return;
- m_toInstallComponentIdReasonHash.insert(component->name(),
- qMakePair(installReason, referencedComponentName));
+ return m_toInstallComponentIdReasonHash.value(c->name()).first;
}
-InstallerCalculator::InstallReasonType InstallerCalculator::installReasonType(Component *c) const
-{
- return m_toInstallComponentIdReasonHash.value(c->name(),
- qMakePair(InstallerCalculator::Selected, QString())).first;
-}
-
-QString InstallerCalculator::installReasonReferencedComponent(Component *component) const
-{
- return m_toInstallComponentIdReasonHash.value(component->name(),
- qMakePair(InstallerCalculator::Selected, QString())).second;
-}
-
-QString InstallerCalculator::installReason(Component *component) const
+QString InstallerCalculator::installReason(const Component *component) const
{
InstallerCalculator::InstallReasonType reason = installReasonType(component);
switch (reason) {
@@ -100,69 +82,98 @@ QString InstallerCalculator::componentsToInstallError() const
return m_componentsToInstallError;
}
-void InstallerCalculator::realAppendToInstallComponents(Component *component, const QString &version)
-{
- if (!component->isInstalled(version) || component->updateRequested()) {
- m_orderedComponentsToInstall.append(component);
- m_toInstallComponentIds.insert(component->name());
- }
-}
-
-QString InstallerCalculator::recursionError(Component *component)
-{
- return QCoreApplication::translate("InstallerCalculator", "Recursion detected, component \"%1\" "
- "already added with reason: \"%2\"").arg(component->name(), installReason(component));
-}
-
-bool InstallerCalculator::appendComponentsToInstall(const QList<Component *> &components)
+bool InstallerCalculator::appendComponentsToInstall(const QList<Component *> &components, bool modelReset, const bool revertFromInstall)
{
if (components.isEmpty())
return true;
QList<Component*> notAppendedComponents; // for example components with unresolved dependencies
- foreach (Component *component, components){
+ foreach (Component *component, components) {
+ if (!component)
+ continue;
+ // When model has been reseted, there should not be components with the same name
if (m_toInstallComponentIds.contains(component->name())) {
- const QString errorMessage = recursionError(component);
- qCWarning(QInstaller::lcInstallerInstallLog).noquote() << errorMessage;
- m_componentsToInstallError.append(errorMessage);
- Q_ASSERT_X(!m_toInstallComponentIds.contains(component->name()), Q_FUNC_INFO,
- qPrintable(errorMessage));
- return false;
+ if (modelReset) {
+ const QString errorMessage = recursionError(component);
+ qCWarning(QInstaller::lcInstallerInstallLog).noquote() << errorMessage;
+ m_componentsToInstallError.append(errorMessage);
+ Q_ASSERT_X(!m_toInstallComponentIds.contains(component->name()), Q_FUNC_INFO,
+ qPrintable(errorMessage));
+ return false;
+ }
+ if (!revertFromInstall) {
+ // We can end up here if component is already added as dependency and
+ // user explicitly selects it to install
+ continue;
+ }
}
if (component->dependencies().isEmpty())
- realAppendToInstallComponents(component);
+ realAppendToInstallComponents(component, QString(), revertFromInstall);
else
notAppendedComponents.append(component);
}
foreach (Component *component, notAppendedComponents) {
- if (!appendComponentToInstall(component))
+ if (!appendComponentToInstall(component, QString(), revertFromInstall))
return false;
}
- QList<Component *> foundAutoDependOnList;
// All regular dependencies are resolved. Now we are looking for auto depend on components.
- foreach (Component *component, m_allComponents) {
- // If a components is already installed or is scheduled for installation, no need to check
- // for auto depend installation.
- if ((!component->isInstalled() || component->updateRequested())
- && !m_toInstallComponentIds.contains(component->name())) {
- // If we figure out a component requests auto installation, keep it to resolve
- // their dependencies as well.
- if (component->isAutoDependOn(m_toInstallComponentIds)) {
- foundAutoDependOnList.append(component);
- insertInstallReason(component, InstallerCalculator::Automatic);
- }
- }
- }
+ QSet<Component *> foundAutoDependOnList = autodependencyComponents(revertFromInstall);
if (!foundAutoDependOnList.isEmpty())
- return appendComponentsToInstall(foundAutoDependOnList);
+ return appendComponentsToInstall(foundAutoDependOnList.values(), modelReset, revertFromInstall);
+
return true;
}
-bool InstallerCalculator::appendComponentToInstall(Component *component, const QString &version)
+bool InstallerCalculator::removeComponentsFromInstall(const QList<Component *> &components)
+{
+ return appendComponentsToInstall(components, false, true);
+}
+
+QString InstallerCalculator::installReasonReferencedComponent(const Component *component) const
+{
+ const QString componentName = component->name();
+ if (m_referenceCount.contains(componentName))
+ return m_referenceCount.value(componentName).first();
+ return m_toInstallComponentIdReasonHash.value(componentName,
+ qMakePair(InstallerCalculator::Selected, QString())).second;
+}
+
+void InstallerCalculator::insertInstallReason(const Component *component,
+ const InstallReasonType installReason, const QString &referencedComponentName, const bool revertFromInstall)
+{
+ if (revertFromInstall && m_toInstallComponentIdReasonHash.contains(component->name())) {
+ m_toInstallComponentIdReasonHash.remove(component->name());
+ } else if (!m_toInstallComponentIdReasonHash.contains(component->name())) {
+ m_toInstallComponentIdReasonHash.insert(component->name(),
+ qMakePair(installReason, referencedComponentName));
+ }
+}
+
+void InstallerCalculator::realAppendToInstallComponents(Component *component, const QString &version, const bool revertFromInstall)
+{
+ if (!m_componentsForAutodepencencyCheck.contains(component))
+ m_componentsForAutodepencencyCheck.append(component);
+ if (revertFromInstall) {
+ if (m_toInstallComponentIds.contains(component->name())) {
+ // Component is no longer added as dependency and is not explicitly selected for install by user
+ if (m_referenceCount.value(component->name()).isEmpty() && !component->isSelected()) {
+ m_toInstallComponentIds.remove(component->name());
+ m_orderedComponentsToInstall.removeAll(component);
+ }
+ }
+ } else {
+ if (!component->isInstalled(version) || component->updateRequested()) {
+ m_toInstallComponentIds.insert(component->name());
+ m_orderedComponentsToInstall.append(component);
+ }
+ }
+}
+
+bool InstallerCalculator::appendComponentToInstall(Component *component, const QString &version, bool revertFromInstall)
{
const QStringList dependenciesList = component->dependencies();
QSet<QString> allDependencies(dependenciesList.begin(), dependenciesList.end());
@@ -185,6 +196,8 @@ bool InstallerCalculator::appendComponentToInstall(Component *component, const Q
return false;
}
}
+ if (revertFromInstall && dependencyComponent->forcedInstallation())
+ continue;
//Check if component requires higher version than what might be already installed
bool isUpdateRequired = false;
QString requiredName;
@@ -203,11 +216,38 @@ bool InstallerCalculator::appendComponentToInstall(Component *component, const Q
requiredDependencyVersion = requiredVersion;
}
}
+
+ // Component can be requested for install by several component (as a dependency).
+ // Keep the reference count to a component, so we know when component needs to be
+ // removed from install.
+ if (!revertFromInstall && m_toInstallComponentIds.contains(dependencyComponentName)) {
+ QStringList value = m_referenceCount.value(dependencyComponentName, QStringList());
+ if (!value.contains(component->name()))
+ value << component->name();
+ m_referenceCount.insert(dependencyComponentName, value);
+ }
+ if (revertFromInstall) {
+ if (m_toInstallComponentIds.contains(dependencyComponentName)
+ && m_referenceCount.contains(dependencyComponentName)) {
+ QStringList value = m_referenceCount.value(dependencyComponentName);
+ if (value.contains(component->name()))
+ value.removeOne(component->name());
+ if (value.isEmpty())
+ m_referenceCount.remove(dependencyComponentName);
+ else
+ m_referenceCount.insert(dependencyComponentName, value);
+ }
+ insertInstallReason(dependencyComponent, InstallerCalculator::Dependent, component->name(), true);
+ if (!appendComponentToInstall(dependencyComponent, requiredDependencyVersion, revertFromInstall))
+ return false;
+ m_visitedComponents.remove(component);
+ }
+
//Check dependencies only if
//- Dependency is not installed or update requested, nor newer version of dependency component required
//- And dependency component is not already added for install
//- And component is not already added for install, then dependencies are already resolved
- if (((!dependencyComponent->isInstalled() || dependencyComponent->updateRequested())
+ if (!revertFromInstall && ((!dependencyComponent->isInstalled() || dependencyComponent->updateRequested())
|| isUpdateRequired) && (!m_toInstallComponentIds.contains(dependencyComponent->name())
&& !m_toInstallComponentIds.contains(component->name()))) {
if (m_visitedComponents.value(component).contains(dependencyComponent)) {
@@ -220,20 +260,66 @@ bool InstallerCalculator::appendComponentToInstall(Component *component, const Q
}
m_visitedComponents[component].insert(dependencyComponent);
- // add needed dependency components to the next run
- insertInstallReason(dependencyComponent, InstallerCalculator::Dependent,
- component->name());
-
- if (!appendComponentToInstall(dependencyComponent, requiredDependencyVersion))
+ QStringList value = m_referenceCount.value(dependencyComponentName, QStringList());
+ if (!value.contains(component->name()))
+ value << component->name();
+ m_referenceCount.insert(dependencyComponentName, value);
+ insertInstallReason(dependencyComponent, InstallerCalculator::Dependent, component->name());
+ if (!appendComponentToInstall(dependencyComponent, requiredDependencyVersion, revertFromInstall))
return false;
}
}
-
- if (!m_toInstallComponentIds.contains(component->name())) {
- realAppendToInstallComponents(component, requiredDependencyVersion);
+ if (!revertFromInstall && !m_toInstallComponentIds.contains(component->name())) {
+ realAppendToInstallComponents(component, requiredDependencyVersion, revertFromInstall);
insertInstallReason(component, InstallerCalculator::Resolved);
}
+ if (revertFromInstall && m_toInstallComponentIds.contains(component->name())) {
+ realAppendToInstallComponents(component, requiredDependencyVersion, revertFromInstall);
+ }
return true;
}
+QString InstallerCalculator::recursionError(const Component *component) const
+{
+ return QCoreApplication::translate("InstallerCalculator", "Recursion detected, component \"%1\" "
+ "already added with reason: \"%2\"").arg(component->name(), installReason(component));
+}
+
+QSet<Component *> InstallerCalculator::autodependencyComponents(const bool revertFromInstall)
+{
+ // All regular dependencies are resolved. Now we are looking for auto depend on components.
+ // m_componentsForAutodepencencyCheck is a list of recently calculated components to be installed
+ // (normal components and regular dependencies components), and we check possible installable auto
+ // dependency components based on that list.
+ QSet<Component *> foundAutoDependOnList;
+ for (const Component *component : qAsConst(m_componentsForAutodepencencyCheck)) {
+ if (!m_autoDependencyComponentHash.contains(component->name()))
+ continue;
+ for (const QString& autoDependency : m_autoDependencyComponentHash.value(component->name())) {
+ // If a components is already installed or is scheduled for installation, no need to check
+ // for auto depend installation.
+ if ((!revertFromInstall && m_toInstallComponentIds.contains(autoDependency))
+ || (revertFromInstall && !m_toInstallComponentIds.contains(autoDependency))) {
+ continue;
+ }
+ Component *autoDependComponent = PackageManagerCore::componentByName(autoDependency, m_allComponents);
+ if (!autoDependComponent)
+ continue;
+ if ((!autoDependComponent->isInstalled() || autoDependComponent->updateRequested())
+ && !m_toInstallComponentIds.contains(autoDependComponent->name())) {
+ // One of the components autodependons is requested for install, check if there
+ // are other autodependencies as well
+ if (autoDependComponent->isAutoDependOn(m_toInstallComponentIds)) {
+ foundAutoDependOnList.insert(autoDependComponent);
+ insertInstallReason(autoDependComponent, InstallerCalculator::Automatic);
+ }
+ } else if (revertFromInstall && m_toInstallComponentIds.contains(autoDependComponent->name())) {
+ foundAutoDependOnList.insert(autoDependComponent);
+ }
+ }
+ }
+ m_componentsForAutodepencencyCheck.clear();
+ return foundAutoDependOnList;
+}
+
} // namespace QInstaller
diff --git a/src/libs/installer/installercalculator.h b/src/libs/installer/installercalculator.h
index b2d05bdbe..2841d8671 100644
--- a/src/libs/installer/installercalculator.h
+++ b/src/libs/installer/installercalculator.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -42,41 +42,50 @@ class Component;
class INSTALLER_EXPORT InstallerCalculator
{
public:
- InstallerCalculator(const QList<Component *> &allComponents);
+ InstallerCalculator(const QList<Component *> &allComponents, const QHash<QString, QStringList> &autoDependencyComponentHash);
enum InstallReasonType
{
+ Selected, // "Selected Component(s) without Dependencies"
Automatic, // "Component(s) added as automatic dependencies"
Dependent, // "Added as dependency for %1."
- Resolved, // "Component(s) that have resolved Dependencies"
- Selected // "Selected Component(s) without Dependencies"
+ Resolved // "Component(s) that have resolved Dependencies"
};
- InstallReasonType installReasonType(Component *component) const;
- QString installReasonReferencedComponent(Component *component) const;
- QString installReason(Component *component) const;
+ InstallReasonType installReasonType(const Component *c) const;
+ QString installReason(const Component *component) const;
QList<Component*> orderedComponentsToInstall() const;
QString componentsToInstallError() const;
- bool appendComponentsToInstall(const QList<Component*> &components);
+ bool appendComponentsToInstall(const QList<Component*> &components, bool modelReset = false, const bool revertFromInstall = false);
+ bool removeComponentsFromInstall(const QList<Component*> &components);
private:
- void insertInstallReason(Component *component,
- InstallReasonType installReasonType,
- const QString &referencedComponentName = QString());
- void realAppendToInstallComponents(Component *component, const QString &version = QString());
- bool appendComponentToInstall(Component *components, const QString &version = QString());
- QString recursionError(Component *component);
+ QString installReasonReferencedComponent(const Component *component) const;
+ void insertInstallReason(const Component *component,
+ const InstallReasonType installReason,
+ const QString &referencedComponentName = QString(),
+ const bool revertFromInstall = false);
+ void realAppendToInstallComponents(Component *component, const QString &version, const bool revertFromInstall);
+ bool appendComponentToInstall(Component *component, const QString &version, const bool revertFromInstall);
+ QString recursionError(const Component *component) const;
+ QSet<Component *> autodependencyComponents(const bool revertFromInstall);
+private:
QList<Component*> m_allComponents;
QHash<Component*, QSet<Component*> > m_visitedComponents;
- QSet<QString> m_toInstallComponentIds; //for faster lookups
+ QList<const Component*> m_componentsForAutodepencencyCheck;
+ //for faster lookups.
+ QSet<QString> m_toInstallComponentIds;
+ QHash<QString, QStringList> m_referenceCount;
QString m_componentsToInstallError;
//calculate installation order variables
QList<Component*> m_orderedComponentsToInstall;
//we can't use this reason hash as component id hash, because some reasons are ready before
//the component is added
QHash<QString, QPair<InstallReasonType, QString> > m_toInstallComponentIdReasonHash;
+ //Helper hash for quicker search for autodependency components
+ QHash<QString, QStringList> m_autoDependencyComponentHash;
};
}
diff --git a/src/libs/installer/packagemanagercore.cpp b/src/libs/installer/packagemanagercore.cpp
index b6f79a92b..041c0fd31 100644
--- a/src/libs/installer/packagemanagercore.cpp
+++ b/src/libs/installer/packagemanagercore.cpp
@@ -583,22 +583,10 @@ void PackageManagerCore::componentsToInstallNeedsRecalculation()
QList<Component*> selectedComponentsToInstall = componentsMarkedForInstallation();
d->m_componentsToInstallCalculated =
- d->installerCalculator()->appendComponentsToInstall(selectedComponentsToInstall);
-
- QList<Component *> componentsToInstall = d->installerCalculator()->orderedComponentsToInstall();
+ d->installerCalculator()->appendComponentsToInstall(selectedComponentsToInstall, true);
d->calculateUninstallComponents();
-
- QSet<Component *> componentsToUninstall = d->uninstallerCalculator()->componentsToUninstall();
-
- foreach (Component *component, components(ComponentType::All))
- component->setInstallAction(component->isInstalled()
- ? ComponentModelHelper::KeepInstalled
- : ComponentModelHelper::KeepUninstalled);
- foreach (Component *component, componentsToUninstall)
- component->setInstallAction(ComponentModelHelper::Uninstall);
- foreach (Component *component, componentsToInstall)
- component->setInstallAction(ComponentModelHelper::Install);
+ d->updateComponentCheckedState();
// update all nodes uncompressed size
foreach (Component *const component, components(ComponentType::Root))
@@ -606,6 +594,59 @@ void PackageManagerCore::componentsToInstallNeedsRecalculation()
}
/*!
+ Calculates components to install based on user selection. \a indexes
+ contains list of model indexes user has selected for install, dependencies
+ and autodependencies are resolved later.
+ */
+void PackageManagerCore::calculateUserSelectedComponentsToInstall(const QList<QModelIndex> &indexes)
+{
+ QList<Component*> componentsToInstall;
+ QList<Component*> componentsToUnInstall;
+ ComponentModel *model = isUpdater() ? updaterComponentModel() : defaultComponentModel();
+ for (QModelIndex index : indexes) {
+ Component *installComponent = model->componentFromIndex(index);
+ // 1. Component is selected for install
+ if (installComponent->isSelected() && !installComponent->isInstalled()) {
+ componentsToInstall.append(installComponent);
+ // Check if component has replacements that needs to be removed
+ const QList<Component*> replacedComponents = d->replacedComponentsByName(installComponent->name());
+ for (Component *replacedComponent : replacedComponents) {
+ componentsToUnInstall.append(replacedComponent);
+ d->uninstallerCalculator()->insertUninstallReason(replacedComponent,
+ UninstallerCalculator::UninstallReasonType::Replaced);
+ }
+ }
+ // 2. Component is reseleted for install (tapping checkbox off/on)
+ else if (installComponent->isSelected() && installComponent->isInstalled()
+ && !d->installerCalculator()->orderedComponentsToInstall().contains(installComponent)) {
+ componentsToInstall.append(installComponent);
+ }
+ // 3. Component is selected for uninstall
+ else if (!isUpdater() && !installComponent->isSelected() && installComponent->isInstalled()) {
+ componentsToUnInstall.append(installComponent);
+ }
+ // 4. Component is reselected for uninstall (tapping checkbox on/off)
+ else if (!installComponent->isSelected()
+ && d->installerCalculator()->orderedComponentsToInstall().contains(installComponent)) {
+ componentsToUnInstall.append(installComponent);
+ // Check if component has replacements that needs to be readded
+ componentsToInstall.append(d->replacedComponentsByName(installComponent->name()));
+ }
+ }
+
+ d->installerCalculator()->removeComponentsFromInstall(componentsToUnInstall);
+ d->m_componentsToInstallCalculated
+ = d->installerCalculator()->appendComponentsToInstall(componentsToInstall, false);
+ if (!isUpdater()) {
+ d->uninstallerCalculator()->appendComponentsToUninstall(componentsToUnInstall, false);
+ }
+ d->uninstallerCalculator()->removeComponentsFromUnInstall(componentsToInstall);
+
+ d->updateComponentCheckedState();
+}
+
+
+/*!
Forces a recalculation of components to install.
\sa {installer::clearComponentsToInstallCalculated}{installer.clearComponentsToInstallCalculated}
*/
@@ -2141,8 +2182,7 @@ QList<Component*> PackageManagerCore::orderedComponentsToInstall() const
bool PackageManagerCore::calculateComponents(QString *displayString)
{
QString htmlOutput;
- if (!calculateComponentsToUninstall() ||
- !calculateComponentsToInstall()) {
+ if (!calculateComponentsToInstall()) {
htmlOutput.append(QString::fromLatin1("<h2><font color=\"red\">%1</font></h2><ul>")
.arg(tr("Cannot resolve all dependencies.")));
//if we have a missing dependency or a recursion we can display it
@@ -3942,8 +3982,12 @@ void PackageManagerCore::storeReplacedComponents(QHash<QString, Component *> &co
components.remove(key);
d->m_deletedReplacedComponents.append(componentToReplace);
}
- d->componentsToReplace().insert(componentName, qMakePair(it.key(), componentToReplace));
d->replacementDependencyComponents().append(componentToReplace);
+
+ //Following hashes are created for quicker search of components
+ d->componentsToReplace().insert(componentName, qMakePair(it.key(), componentToReplace));
+ QStringList oldValue = d->componentReplaces().value(it.key()->name());
+ d->componentReplaces().insert(it.key()->name(), oldValue << componentToReplace->name());
}
}
}
@@ -4205,8 +4249,8 @@ bool PackageManagerCore::fetchUpdaterPackages(const PackagesList &remotes, const
if (!component->isUnstable())
component->setCheckState(Qt::Checked);
}
+ d->createDependencyHashes(component);
}
-
if (foundEssentialUpdate()) {
foreach (QInstaller::Component *component, components) {
if (d->statusCanceledOrFailed())
@@ -4379,9 +4423,10 @@ ComponentModel *PackageManagerCore::componentModel(PackageManagerCore *core, con
ComponentModel::tr("Release Date"));
model->setHeaderData(ComponentModelHelper::UncompressedSizeColumn, Qt::Horizontal,
ComponentModel::tr("Size"));
- connect(model, SIGNAL(checkStateChanged(QInstaller::ComponentModel::ModelState)), this,
- SLOT(componentsToInstallNeedsRecalculation()));
-
+ connect(model, &ComponentModel::modelCheckStateChanged,
+ this, &PackageManagerCore::componentsToInstallNeedsRecalculation);
+ connect(model, &ComponentModel::componentsCheckStateChanged,
+ this, &PackageManagerCore::calculateUserSelectedComponentsToInstall);
return model;
}
diff --git a/src/libs/installer/packagemanagercore.h b/src/libs/installer/packagemanagercore.h
index 7cce3f7be..bebfc191d 100644
--- a/src/libs/installer/packagemanagercore.h
+++ b/src/libs/installer/packagemanagercore.h
@@ -352,6 +352,7 @@ public Q_SLOTS:
void setCompleteUninstallation(bool complete);
void cancelMetaInfoJob();
void componentsToInstallNeedsRecalculation();
+ void calculateUserSelectedComponentsToInstall(const QList<QModelIndex> &indexes);
void clearComponentsToInstallCalculated();
Q_SIGNALS:
@@ -437,6 +438,7 @@ private:
PackageManagerCorePrivate *const d;
friend class PackageManagerCorePrivate;
QHash<QString, QString> m_fileDialogAutomaticAnswers;
+ QHash<QString, QStringList> m_localVirtualWithDependants;
private:
// remove once we deprecate isSelected, setSelected etc...
diff --git a/src/libs/installer/packagemanagercore_p.cpp b/src/libs/installer/packagemanagercore_p.cpp
index 73738d1cb..fc7a8e2c0 100644
--- a/src/libs/installer/packagemanagercore_p.cpp
+++ b/src/libs/installer/packagemanagercore_p.cpp
@@ -430,12 +430,13 @@ bool PackageManagerCorePrivate::buildComponentTree(QHash<QString, Component*> &c
m_core->appendRootComponent(component);
}
- // after everything is set up, load the scripts if needed
- if (loadScript) {
- foreach (QInstaller::Component *component, components)
+ // after everything is set up, load the scripts if needed and create helper hashes
+ // for autodependency and dependency components for quicker search later
+ foreach (QInstaller::Component *component, components) {
+ if (loadScript)
component->loadComponentScript();
+ createDependencyHashes(component);
}
-
// now we can preselect components in the tree
foreach (QInstaller::Component *component, components) {
// set the checked state for all components without child (means without tristate)
@@ -490,6 +491,10 @@ bool PackageManagerCorePrivate::buildComponentTree(QHash<QString, Component*> &c
void PackageManagerCorePrivate::cleanUpComponentEnvironment()
{
+ m_componentReplaces.clear();
+ m_autoDependencyComponentHash.clear();
+ m_dependencyComponentHash.clear();
+ m_localVirtualComponents.clear();
// clean up registered (downloaded) data
if (m_core->isMaintainer())
BinaryFormatEngineHandler::instance()->clear();
@@ -565,6 +570,26 @@ QHash<QString, QPair<Component*, Component*> > &PackageManagerCorePrivate::compo
return (!isUpdater()) ? m_componentsToReplaceAllMode : m_componentsToReplaceUpdaterMode;
}
+QHash<QString, QStringList> &PackageManagerCorePrivate::componentReplaces()
+{
+ return m_componentReplaces;
+}
+
+QList<Component*> PackageManagerCorePrivate::replacedComponentsByName(const QString &name)
+{
+ // Creates a list of components which are replaced by component 'name'
+ QList<Component*> replacedComponents;
+ if (m_componentReplaces.contains(name)) {
+ for (const QString &replacedComponentName : m_componentReplaces.value(name)) {
+ Component *replacedComponent = m_core->componentByName(replacedComponentName,
+ m_core->components(PackageManagerCore::ComponentType::All));
+ if (replacedComponent)
+ replacedComponents.append(replacedComponent);
+ }
+ }
+ return replacedComponents;
+}
+
void PackageManagerCorePrivate::clearInstallerCalculator()
{
delete m_installerCalculator;
@@ -576,7 +601,7 @@ InstallerCalculator *PackageManagerCorePrivate::installerCalculator() const
if (!m_installerCalculator) {
PackageManagerCorePrivate *const pmcp = const_cast<PackageManagerCorePrivate *> (this);
pmcp->m_installerCalculator = new InstallerCalculator(
- m_core->components(PackageManagerCore::ComponentType::AllNoReplacements));
+ m_core->components(PackageManagerCore::ComponentType::AllNoReplacements), pmcp->m_autoDependencyComponentHash);
}
return m_installerCalculator;
}
@@ -600,7 +625,8 @@ UninstallerCalculator *PackageManagerCorePrivate::uninstallerCalculator() const
}
}
- pmcp->m_uninstallerCalculator = new UninstallerCalculator(installedComponents, m_core);
+ pmcp->m_uninstallerCalculator = new UninstallerCalculator(installedComponents, m_core,
+ pmcp->m_autoDependencyComponentHash, pmcp->m_dependencyComponentHash, pmcp->m_localVirtualComponents);
}
return m_uninstallerCalculator;
}
@@ -2685,8 +2711,11 @@ LocalPackagesHash PackageManagerCorePrivate::localInstalledPackages()
if (statusCanceledOrFailed())
break;
installedPackages.insert(package.name, package);
+ if (package.virtualComp && package.autoDependencies.isEmpty()) {
+ if (!m_localVirtualComponents.contains(package.name))
+ m_localVirtualComponents.append(package.name);
+ }
}
-
return installedPackages;
}
@@ -2823,6 +2852,19 @@ void PackageManagerCorePrivate::storeCheckState()
m_coreCheckedHash.insert(component, component->checkState());
}
+void PackageManagerCorePrivate::updateComponentCheckedState()
+{
+ for (Component *component : m_core->components(PackageManagerCore::ComponentType::All)) {
+ component->setInstallAction(component->isInstalled()
+ ? ComponentModelHelper::KeepInstalled
+ : ComponentModelHelper::KeepUninstalled);
+ }
+ for (Component *component : uninstallerCalculator()->componentsToUninstall())
+ component->setInstallAction(ComponentModelHelper::Uninstall);
+ for (Component *component : installerCalculator()->orderedComponentsToInstall())
+ component->setInstallAction(ComponentModelHelper::Install);
+}
+
void PackageManagerCorePrivate::connectOperationCallMethodRequest(Operation *const operation)
{
QObject *const operationObject = dynamic_cast<QObject *> (operation);
@@ -3093,4 +3135,21 @@ void PackageManagerCorePrivate::commitPendingUnstableComponents()
m_pendingUnstableComponents.clear();
}
+void PackageManagerCorePrivate::createDependencyHashes(const Component* component)
+{
+ for (const QString &autodepend : component->autoDependencies()) {
+ QStringList value = m_autoDependencyComponentHash.value(autodepend);
+ if (!value.contains(component->name()))
+ value.append(component->name());
+ m_autoDependencyComponentHash.insert(autodepend, value);
+ }
+
+ for (const QString &depend : component->dependencies()) {
+ QStringList value = m_dependencyComponentHash.value(depend);
+ if (!value.contains(component->name()))
+ value.append(component->name());
+ m_dependencyComponentHash.insert(depend, value);
+ }
+}
+
} // namespace QInstaller
diff --git a/src/libs/installer/packagemanagercore_p.h b/src/libs/installer/packagemanagercore_p.h
index 8c5191dea..8e1184c58 100644
--- a/src/libs/installer/packagemanagercore_p.h
+++ b/src/libs/installer/packagemanagercore_p.h
@@ -111,6 +111,8 @@ public:
void clearUpdaterComponentLists();
QList<Component*> &replacementDependencyComponents();
QHash<QString, QPair<Component*, Component*> > &componentsToReplace();
+ QHash<QString, QStringList > &componentReplaces();
+ QList<Component*> replacedComponentsByName(const QString &name);
void clearInstallerCalculator();
InstallerCalculator *installerCalculator() const;
@@ -262,6 +264,12 @@ private:
bool askUserConfirmCommand() const;
bool packageNeedsUpdate(const LocalPackage &localPackage, const Package *update) const;
void commitPendingUnstableComponents();
+ void createDependencyHashes(const Component* component);
+ void updateComponentCheckedState();
+
+ // remove once we deprecate isSelected, setSelected etc...
+ void restoreCheckState();
+ void storeCheckState();
private:
PackageManagerCore *m_core;
@@ -296,12 +304,15 @@ private:
QScopedPointer<RemoteFileEngineHandler> m_remoteFileEngineHandler;
QHash<QString, QVariantMap> m_licenseItems;
-private:
- // remove once we deprecate isSelected, setSelected etc...
- void restoreCheckState();
- void storeCheckState();
QHash<Component*, Qt::CheckState> m_coreCheckedHash;
QList<Component*> m_deletedReplacedComponents;
+ AutoDependencyHash m_autoDependencyComponentHash;
+ DependencyHash m_dependencyComponentHash;
+
+ QStringList m_localVirtualComponents;
+
+ // < name (component replacing others), components to replace>
+ QHash<QString, QStringList > m_componentReplaces;
};
} // namespace QInstaller
diff --git a/src/libs/installer/qinstallerglobal.cpp b/src/libs/installer/qinstallerglobal.cpp
index 177a2595d..6a67e9e10 100644
--- a/src/libs/installer/qinstallerglobal.cpp
+++ b/src/libs/installer/qinstallerglobal.cpp
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2020 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -70,3 +70,15 @@
Synonym for QHash<QString, KDUpdater::LocalPackage>.
*/
+
+/*!
+ \typedef QInstaller::AutoDependencyHash
+
+ Synonym for QHash<QString, QStringList>.
+*/
+
+/*!
+ \typedef QInstaller::DependencyHash
+
+ Synonym for QHash<QString, QStringList>.
+*/
diff --git a/src/libs/installer/qinstallerglobal.h b/src/libs/installer/qinstallerglobal.h
index 884044db9..98a81f092 100644
--- a/src/libs/installer/qinstallerglobal.h
+++ b/src/libs/installer/qinstallerglobal.h
@@ -1,6 +1,6 @@
/**************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -57,6 +57,9 @@ typedef QList<QInstaller::Package*> PackagesList;
typedef QHash<QString, KDUpdater::LocalPackage> LocalPackagesHash;
+typedef QHash<QString, QStringList> AutoDependencyHash;
+typedef QHash<QString, QStringList> DependencyHash;
+
} // namespace QInstaller
#endif // QINSTALLER_GLOBAL_H
diff --git a/src/libs/installer/uninstallercalculator.cpp b/src/libs/installer/uninstallercalculator.cpp
index a8c47e523..9bcacb246 100644
--- a/src/libs/installer/uninstallercalculator.cpp
+++ b/src/libs/installer/uninstallercalculator.cpp
@@ -42,9 +42,16 @@ namespace QInstaller {
\internal
*/
-UninstallerCalculator::UninstallerCalculator(const QList<Component *> &installedComponents, PackageManagerCore *core)
+UninstallerCalculator::UninstallerCalculator(const QList<Component *> &installedComponents
+ , PackageManagerCore *core
+ , const QHash<QString, QStringList> &autoDependencyComponentHash
+ , const QHash<QString, QStringList> &dependencyComponentHash
+ , const QStringList &localVirtualComponents)
: m_installedComponents(installedComponents)
, m_core(core)
+ , m_autoDependencyComponentHash(autoDependencyComponentHash)
+ , m_dependencyComponentHash(dependencyComponentHash)
+ , m_localVirtualComponents(localVirtualComponents)
{
}
@@ -53,7 +60,7 @@ QSet<Component *> UninstallerCalculator::componentsToUninstall() const
return m_componentsToUninstall;
}
-void UninstallerCalculator::appendComponentToUninstall(Component *component)
+void UninstallerCalculator::appendComponentToUninstall(Component *component, const bool reverse)
{
if (!component)
return;
@@ -61,79 +68,64 @@ void UninstallerCalculator::appendComponentToUninstall(Component *component)
if (!component->isInstalled())
return;
- // remove all already resolved dependees
- const QList<Component *> dependeesList = m_core->dependees(component);
- QSet<Component *> dependees = QSet<Component *>(dependeesList.begin(),
- dependeesList.end()).subtract(m_componentsToUninstall);
-
- foreach (Component *dependee, dependees) {
- appendComponentToUninstall(dependee);
- insertUninstallReason(dependee, UninstallerCalculator::Dependent, component->name());
+ if (m_dependencyComponentHash.contains(component->name())) {
+ const QStringList &dependencies = PackageManagerCore::parseNames(m_dependencyComponentHash.value(component->name()));
+ for (const QString &dependencyComponent : dependencies) {
+ Component *depComponent = m_core->componentByName(dependencyComponent);
+ if (depComponent && depComponent->isInstalled() && !m_componentsToUninstall.contains(depComponent)) {
+ appendComponentToUninstall(depComponent, reverse);
+ insertUninstallReason(depComponent, UninstallerCalculator::Dependent, component->name());
+ } else if (reverse) {
+ appendComponentToUninstall(depComponent, true);
+ }
+ }
+ }
+ if (reverse) {
+ m_componentsToUninstall.remove(component);
+ } else {
+ m_componentsToUninstall.insert(component);
}
-
- m_componentsToUninstall.insert(component);
}
-void UninstallerCalculator::appendComponentsToUninstall(const QList<Component*> &components)
+void UninstallerCalculator::appendComponentsToUninstall(const QList<Component*> &components, const bool reverse)
{
+ if (components.isEmpty())
+ return;
foreach (Component *component, components)
- appendComponentToUninstall(component);
-
+ appendComponentToUninstall(component, reverse);
QList<Component*> autoDependOnList;
// All regular dependees are resolved. Now we are looking for auto depend on components.
- foreach (Component *component, m_installedComponents) {
+ for (Component *component : components) {
// If a components is installed and not yet scheduled for un-installation, check for auto depend.
- if (component->isInstalled() && !m_componentsToUninstall.contains(component)) {
- QStringList autoDependencies = PackageManagerCore::parseNames(component->autoDependencies());
- if (autoDependencies.isEmpty())
- continue;
-
- // This code needs to be enabled once the scripts use isInstalled, installationRequested and
- // uninstallationRequested...
- if (autoDependencies.first().compare(scScript, Qt::CaseInsensitive) == 0) {
- //QScriptValue valueFromScript;
- //try {
- // valueFromScript = callScriptMethod(QLatin1String("isAutoDependOn"));
- //} catch (const Error &error) {
- // // keep the component, should do no harm
- // continue;
- //}
-
- //if (valueFromScript.isValid() && !valueFromScript.toBool())
- // autoDependOnList.append(component);
- continue;
- }
-
- foreach (Component *c, m_installedComponents) {
- const QString replaces = c->value(scReplaces);
- const QStringList possibleNames = replaces.split(QInstaller::commaRegExp(),
- Qt::SkipEmptyParts) << c->name();
- foreach (const QString &possibleName, possibleNames) {
-
- Component *cc = PackageManagerCore::componentByName(possibleName, m_installedComponents);
- if (cc && (cc->installAction() != ComponentModelHelper::AutodependUninstallation)) {
- autoDependencies.removeAll(possibleName);
-
- }
- }
- }
-
- // A component requested auto uninstallation, keep it to resolve their dependencies as well.
- if (!autoDependencies.isEmpty()) {
- autoDependOnList.append(component);
- insertUninstallReason(component, UninstallerCalculator::AutoDependent, autoDependencies.join(QLatin1String(", ")));
- component->setInstallAction(ComponentModelHelper::AutodependUninstallation);
+ if (!m_autoDependencyComponentHash.contains(component->name()))
+ continue;
+ const QStringList autoDependencies = PackageManagerCore::parseNames(m_autoDependencyComponentHash.value(component->name()));
+ for (const QString &autoDependencyComponent : autoDependencies) {
+ Component *autoDepComponent = m_core->componentByName(autoDependencyComponent);
+ if (autoDepComponent && autoDepComponent->isInstalled()) {
+ // A component requested auto uninstallation, keep it to resolve their dependencies as well.
+ if (reverse) {
+ autoDependOnList.append(autoDepComponent);
+ } else if (!m_componentsToUninstall.contains(autoDepComponent)) {
+ insertUninstallReason(autoDepComponent, UninstallerCalculator::AutoDependent, component->name());
+ autoDepComponent->setInstallAction(ComponentModelHelper::AutodependUninstallation);
+ autoDependOnList.append(autoDepComponent);
+ }
}
}
}
-
if (!autoDependOnList.isEmpty())
- appendComponentsToUninstall(autoDependOnList);
+ appendComponentsToUninstall(autoDependOnList, reverse);
else
- appendVirtualComponentsToUninstall();
+ appendVirtualComponentsToUninstall(reverse);
+}
+
+void UninstallerCalculator::removeComponentsFromUnInstall(const QList<Component*> &components)
+{
+ appendComponentsToUninstall(components, true);
}
-void UninstallerCalculator::insertUninstallReason(Component *component, UninstallReasonType uninstallReason,
+void UninstallerCalculator::insertUninstallReason(Component *component, const UninstallReasonType uninstallReason,
const QString &referencedComponentName)
{
// keep the first reason
@@ -176,34 +168,56 @@ QString UninstallerCalculator::uninstallReasonReferencedComponent(Component *com
return m_toUninstallComponentIdReasonHash.value(component->name()).second;
}
-
-void UninstallerCalculator::appendVirtualComponentsToUninstall()
+void UninstallerCalculator::appendVirtualComponentsToUninstall(const bool reverse)
{
QList<Component*> unneededVirtualList;
+
// Check for virtual components without dependees
- for (Component *component : qAsConst(m_installedComponents)) {
- if (component->isInstalled() && component->isVirtual() && !m_componentsToUninstall.contains(component)) {
- // Components with auto dependencies were handled in the previous step
- if (!component->autoDependencies().isEmpty() || component->forcedInstallation())
- continue;
-
- bool required = false;
- // Check if installed or about to be updated -packages are dependant on the package
- for (Component *dependant : m_core->installDependants(component)) {
- if (dependant->isInstalled() && !m_componentsToUninstall.contains(dependant)) {
- required = true;
- break;
+ if (reverse) {
+ for (Component *reverseFromUninstall : qAsConst(m_virtualComponentsForReverse)) {
+ if (m_componentsToUninstall.contains(reverseFromUninstall)) {
+ bool required = false;
+ // Check if installed or about to be updated -packages are dependant on the package
+ const QList<Component*> installDependants = m_core->installDependants(reverseFromUninstall);
+ for (Component *dependant : installDependants) {
+ if (dependant->isInstalled() && !m_componentsToUninstall.contains(dependant)) {
+ required = true;
+ break;
+ }
+ }
+ if (required) {
+ unneededVirtualList.append(reverseFromUninstall);
}
}
- if (!required) {
- unneededVirtualList.append(component);
- insertUninstallReason(component, UninstallerCalculator::VirtualDependent);
+ }
+ } else {
+ for (const QString &componentName : qAsConst(m_localVirtualComponents)) {
+ Component *virtualComponent = m_core->componentByName(componentName);
+ if (virtualComponent->isInstalled() && !m_componentsToUninstall.contains(virtualComponent)) {
+ // Components with auto dependencies were handled in the previous step
+ if (!virtualComponent->autoDependencies().isEmpty() || virtualComponent->forcedInstallation())
+ continue;
+
+ bool required = false;
+ // Check if installed or about to be updated -packages are dependant on the package
+ const QList<Component*> installDependants = m_core->installDependants(virtualComponent);
+ for (Component *dependant : installDependants) {
+ if (dependant->isInstalled() && !m_componentsToUninstall.contains(dependant)) {
+ required = true;
+ break;
+ }
+ }
+ if (!required) {
+ unneededVirtualList.append(virtualComponent);
+ m_virtualComponentsForReverse.append(virtualComponent);
+ insertUninstallReason(virtualComponent, UninstallerCalculator::VirtualDependent);
+ }
}
}
}
if (!unneededVirtualList.isEmpty())
- appendComponentsToUninstall(unneededVirtualList);
+ appendComponentsToUninstall(unneededVirtualList, reverse);
}
} // namespace QInstaller
diff --git a/src/libs/installer/uninstallercalculator.h b/src/libs/installer/uninstallercalculator.h
index c20616e93..8bb9eb814 100644
--- a/src/libs/installer/uninstallercalculator.h
+++ b/src/libs/installer/uninstallercalculator.h
@@ -52,27 +52,34 @@ public:
AutoDependent // "Removed as autodependency component is removed"
};
- UninstallerCalculator(const QList<Component *> &installedComponents, PackageManagerCore *core);
+ UninstallerCalculator(const QList<Component *> &installedComponents, PackageManagerCore *core,
+ const QHash<QString, QStringList> &autoDependencyComponentHash,
+ const QHash<QString, QStringList> &dependencyComponentHash,
+ const QStringList &localVirtualComponents);
QSet<Component*> componentsToUninstall() const;
- void appendComponentsToUninstall(const QList<Component*> &components);
+ void appendComponentsToUninstall(const QList<Component*> &components, const bool reverse = false);
+ void removeComponentsFromUnInstall(const QList<Component*> &components);
void insertUninstallReason(Component *component,
- UninstallReasonType installReasonType,
+ const UninstallReasonType uninstallReason,
const QString &referencedComponentName = QString());
QString uninstallReason(Component *component) const;
UninstallerCalculator::UninstallReasonType uninstallReasonType(Component *c) const;
QString uninstallReasonReferencedComponent(Component *component) const;
private:
-
- void appendComponentToUninstall(Component *component);
- void appendVirtualComponentsToUninstall();
+ void appendComponentToUninstall(Component *component, const bool reverse);
+ void appendVirtualComponentsToUninstall(const bool reverse);
QList<Component *> m_installedComponents;
QSet<Component *> m_componentsToUninstall;
PackageManagerCore *m_core;
QHash<QString, QPair<UninstallReasonType, QString> > m_toUninstallComponentIdReasonHash;
+ QHash<QString, QStringList> m_autoDependencyComponentHash;
+ QHash<QString, QStringList> m_dependencyComponentHash;
+ QStringList m_localVirtualComponents;
+ QList<Component *> m_virtualComponentsForReverse;
};
}