From a28cf55b5a5007c0dd952b3012c076d9da329f0f Mon Sep 17 00:00:00 2001 From: Katja Marttila Date: Fri, 25 Mar 2022 15:38:50 +0200 Subject: 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 --- src/libs/installer/componentmodel.cpp | 41 +++-- src/libs/installer/componentmodel.h | 8 +- src/libs/installer/componentselectionpage_p.cpp | 16 +- src/libs/installer/installercalculator.cpp | 232 ++++++++++++++++-------- src/libs/installer/installercalculator.h | 39 ++-- src/libs/installer/packagemanagercore.cpp | 87 ++++++--- src/libs/installer/packagemanagercore.h | 2 + src/libs/installer/packagemanagercore_p.cpp | 73 +++++++- src/libs/installer/packagemanagercore_p.h | 19 +- src/libs/installer/qinstallerglobal.cpp | 14 +- src/libs/installer/qinstallerglobal.h | 5 +- src/libs/installer/uninstallercalculator.cpp | 170 +++++++++-------- src/libs/installer/uninstallercalculator.h | 19 +- 13 files changed, 491 insertions(+), 234 deletions(-) (limited to 'src') 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 &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 changed = updateCheckedState(nodes << component, newValue); + const QList 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 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 changed; + QList 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 ComponentModel::updateCheckedState(const ComponentSet &components, Qt::CheckState state) +QList ComponentModel::updateCheckedState(const ComponentSet &components, const Qt::CheckState state) { // get all parent nodes for the components we're going to update QMultiMap sortedNodesMap; @@ -567,7 +567,7 @@ QSet ComponentModel::updateCheckedState(const ComponentSet &compone } } - QSet changed; + QList 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 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 &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 updateCheckedState(const ComponentSet &components, Qt::CheckState state); + QList 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 -#include - namespace QInstaller { /*! @@ -43,34 +41,18 @@ namespace QInstaller { \internal */ -InstallerCalculator::InstallerCalculator(const QList &allComponents) +InstallerCalculator::InstallerCalculator(const QList &allComponents, const QHash &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 &components) +bool InstallerCalculator::appendComponentsToInstall(const QList &components, bool modelReset, const bool revertFromInstall) { if (components.isEmpty()) return true; QList 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 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 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 &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 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 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 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 &allComponents); + InstallerCalculator(const QList &allComponents, const QHash &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 orderedComponentsToInstall() const; QString componentsToInstallError() const; - bool appendComponentsToInstall(const QList &components); + bool appendComponentsToInstall(const QList &components, bool modelReset = false, const bool revertFromInstall = false); + bool removeComponentsFromInstall(const QList &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 autodependencyComponents(const bool revertFromInstall); +private: QList m_allComponents; QHash > m_visitedComponents; - QSet m_toInstallComponentIds; //for faster lookups + QList m_componentsForAutodepencencyCheck; + //for faster lookups. + QSet m_toInstallComponentIds; + QHash m_referenceCount; QString m_componentsToInstallError; //calculate installation order variables QList m_orderedComponentsToInstall; //we can't use this reason hash as component id hash, because some reasons are ready before //the component is added QHash > m_toInstallComponentIdReasonHash; + //Helper hash for quicker search for autodependency components + QHash 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,28 +583,69 @@ void PackageManagerCore::componentsToInstallNeedsRecalculation() QList selectedComponentsToInstall = componentsMarkedForInstallation(); d->m_componentsToInstallCalculated = - d->installerCalculator()->appendComponentsToInstall(selectedComponentsToInstall); - - QList componentsToInstall = d->installerCalculator()->orderedComponentsToInstall(); + d->installerCalculator()->appendComponentsToInstall(selectedComponentsToInstall, true); d->calculateUninstallComponents(); - - QSet 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)) component->updateUncompressedSize(); // this is a recursive call } +/*! + 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 &indexes) +{ + QList componentsToInstall; + QList 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 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 PackageManagerCore::orderedComponentsToInstall() const bool PackageManagerCore::calculateComponents(QString *displayString) { QString htmlOutput; - if (!calculateComponentsToUninstall() || - !calculateComponentsToInstall()) { + if (!calculateComponentsToInstall()) { htmlOutput.append(QString::fromLatin1("

%1

    ") .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 &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 &indexes); void clearComponentsToInstallCalculated(); Q_SIGNALS: @@ -437,6 +438,7 @@ private: PackageManagerCorePrivate *const d; friend class PackageManagerCorePrivate; QHash m_fileDialogAutomaticAnswers; + QHash 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 &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 &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 > &PackageManagerCorePrivate::compo return (!isUpdater()) ? m_componentsToReplaceAllMode : m_componentsToReplaceUpdaterMode; } +QHash &PackageManagerCorePrivate::componentReplaces() +{ + return m_componentReplaces; +} + +QList PackageManagerCorePrivate::replacedComponentsByName(const QString &name) +{ + // Creates a list of components which are replaced by component 'name' + QList 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 (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 (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 &replacementDependencyComponents(); QHash > &componentsToReplace(); + QHash &componentReplaces(); + QList 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 m_remoteFileEngineHandler; QHash m_licenseItems; -private: - // remove once we deprecate isSelected, setSelected etc... - void restoreCheckState(); - void storeCheckState(); QHash m_coreCheckedHash; QList m_deletedReplacedComponents; + AutoDependencyHash m_autoDependencyComponentHash; + DependencyHash m_dependencyComponentHash; + + QStringList m_localVirtualComponents; + + // < name (component replacing others), components to replace> + QHash 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. */ + +/*! + \typedef QInstaller::AutoDependencyHash + + Synonym for QHash. +*/ + +/*! + \typedef QInstaller::DependencyHash + + Synonym for QHash. +*/ 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 PackagesList; typedef QHash LocalPackagesHash; +typedef QHash AutoDependencyHash; +typedef QHash 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 &installedComponents, PackageManagerCore *core) +UninstallerCalculator::UninstallerCalculator(const QList &installedComponents + , PackageManagerCore *core + , const QHash &autoDependencyComponentHash + , const QHash &dependencyComponentHash + , const QStringList &localVirtualComponents) : m_installedComponents(installedComponents) , m_core(core) + , m_autoDependencyComponentHash(autoDependencyComponentHash) + , m_dependencyComponentHash(dependencyComponentHash) + , m_localVirtualComponents(localVirtualComponents) { } @@ -53,7 +60,7 @@ QSet 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 dependeesList = m_core->dependees(component); - QSet dependees = QSet(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 &components) +void UninstallerCalculator::appendComponentsToUninstall(const QList &components, const bool reverse) { + if (components.isEmpty()) + return; foreach (Component *component, components) - appendComponentToUninstall(component); - + appendComponentToUninstall(component, reverse); QList 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 &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 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 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 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 &installedComponents, PackageManagerCore *core); + UninstallerCalculator(const QList &installedComponents, PackageManagerCore *core, + const QHash &autoDependencyComponentHash, + const QHash &dependencyComponentHash, + const QStringList &localVirtualComponents); QSet componentsToUninstall() const; - void appendComponentsToUninstall(const QList &components); + void appendComponentsToUninstall(const QList &components, const bool reverse = false); + void removeComponentsFromUnInstall(const QList &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 m_installedComponents; QSet m_componentsToUninstall; PackageManagerCore *m_core; QHash > m_toUninstallComponentIdReasonHash; + QHash m_autoDependencyComponentHash; + QHash m_dependencyComponentHash; + QStringList m_localVirtualComponents; + QList m_virtualComponentsForReverse; }; } -- cgit v1.2.3