diff --git a/src/plugins/projectexplorer/projectimporter.cpp b/src/plugins/projectexplorer/projectimporter.cpp index d4f1d345151..5fc989b193e 100644 --- a/src/plugins/projectexplorer/projectimporter.cpp +++ b/src/plugins/projectexplorer/projectimporter.cpp @@ -40,6 +40,7 @@ #include #include +#include namespace ProjectExplorer { @@ -48,6 +49,26 @@ static const Core::Id KIT_TEMPORARY_NAME("PE.TempName"); static const Core::Id KIT_FINAL_NAME("PE.FinalName"); static const Core::Id TEMPORARY_OF_PROJECTS("PE.TempProject"); +static Core::Id fullId(Core::Id id) +{ + const QString prefix = "PE.Temporary."; + + const QString idStr = id.toString(); + QTC_ASSERT(!idStr.startsWith(prefix), return Core::Id::fromString(idStr)); + + return Core::Id::fromString(prefix + idStr); +} + +static bool hasOtherUsers(Core::Id id, const QVariant &v, Kit *k) +{ + return Utils::contains(KitManager::kits(), [id, v, k](Kit *in) -> bool { + if (in == k) + return false; + QVariantList tmp = in->value(id).toList(); + return tmp.contains(v); + }); +} + ProjectImporter::ProjectImporter(const QString &path) : m_projectPath(path) { } @@ -146,7 +167,7 @@ Target *ProjectImporter::preferredTarget(const QList &possibleTargets) return activeTarget; } -void ProjectImporter::markTemporary(Kit *k) const +void ProjectImporter::markKitAsTemporary(Kit *k) const { QTC_ASSERT(!k->hasValue(KIT_IS_TEMPORARY), return); @@ -161,13 +182,14 @@ void ProjectImporter::markTemporary(Kit *k) const k->setValue(KIT_IS_TEMPORARY, true); } -void ProjectImporter::makePermanent(Kit *k) const +void ProjectImporter::makePersistent(Kit *k) const { if (!k->hasValue(KIT_IS_TEMPORARY)) return; UpdateGuard guard(*this); + KitGuard kitGuard(k); k->removeKey(KIT_IS_TEMPORARY); k->removeKey(TEMPORARY_OF_PROJECTS); const QString tempName = k->value(KIT_TEMPORARY_NAME).toString(); @@ -175,11 +197,38 @@ void ProjectImporter::makePermanent(Kit *k) const k->setUnexpandedDisplayName(k->value(KIT_FINAL_NAME).toString()); k->removeKey(KIT_TEMPORARY_NAME); k->removeKey(KIT_FINAL_NAME); + + foreach (const TemporaryInformationHandler &tih, m_temporaryHandlers) { + const Core::Id fid = fullId(tih.id); + const QVariantList temporaryValues = k->value(fid).toList(); + + // Mark permanent in all other kits: + foreach (Kit *ok, KitManager::kits()) { + if (ok == k) + continue; + + QVariantList otherTemporaryValues = ok->value(fid).toList(); + otherTemporaryValues = Utils::filtered(otherTemporaryValues, [&temporaryValues](const QVariant &v) { + return temporaryValues.contains(v); + }); + ok->setValueSilently(fid, otherTemporaryValues); + } + + // persist: + tih.persist(k, temporaryValues); + } } void ProjectImporter::cleanupKit(Kit *k) { - Q_UNUSED(k); + foreach (const TemporaryInformationHandler &tih, m_temporaryHandlers) { + const Core::Id fid = fullId(tih.id); + QVariantList temporaryValues = k->value(fid).toList(); + temporaryValues = Utils::filtered(temporaryValues, [fid, k](const QVariant &v) { + return !hasOtherUsers(fid, v, k); + }); + tih.cleanup(k, temporaryValues); + } } void ProjectImporter::addProject(Kit *k) @@ -220,7 +269,7 @@ Kit *ProjectImporter::createTemporaryKit(const KitSetupFunction &setup) const { KitGuard kitGuard(k); k->setUnexpandedDisplayName(QCoreApplication::translate("ProjectExplorer::ProjectImporter", "Imported Kit"));; - markTemporary(k); + markKitAsTemporary(k); setup(k); @@ -232,4 +281,37 @@ Kit *ProjectImporter::createTemporaryKit(const KitSetupFunction &setup) const return k; } +bool ProjectImporter::findTemporaryHandler(Core::Id id) const +{ + return Utils::contains(m_temporaryHandlers, [id](const TemporaryInformationHandler &ch) { return ch.id == id; }); +} + +void ProjectImporter::useTemporaryKitInformation(Core::Id id, + ProjectImporter::CleanupFunction cleanup, + ProjectImporter::PersistFunction persist) +{ + QTC_ASSERT(!findTemporaryHandler(id), return); + m_temporaryHandlers.append({ id, cleanup, persist }); +} + +void ProjectImporter::addTemporaryData(Core::Id id, const QVariant &cleanupData, Kit *k) const +{ + QTC_ASSERT(findTemporaryHandler(id), return); + const Core::Id fid = fullId(id); + + KitGuard guard(k); + QVariantList tmp = k->value(fid).toList(); + QTC_ASSERT(!tmp.contains(cleanupData), return); + tmp.append(cleanupData); + k->setValue(fid, tmp); +} + +bool ProjectImporter::hasKitWithTemporaryData(Core::Id id, const QVariant &data) const +{ + Core::Id fid = fullId(id); + return Utils::contains(KitManager::kits(), [data, fid](Kit *k) { + return k->value(fid).toList().contains(data); + }); +} + } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/projectimporter.h b/src/plugins/projectexplorer/projectimporter.h index 86fa1871e11..e6406787f20 100644 --- a/src/plugins/projectexplorer/projectimporter.h +++ b/src/plugins/projectexplorer/projectimporter.h @@ -27,6 +27,8 @@ #include "projectexplorer_export.h" +#include + #include namespace ProjectExplorer { @@ -51,10 +53,8 @@ public: bool isUpdating() const { return m_isUpdating; } - virtual void makePermanent(Kit *k) const; - - // Additional cleanup that has to happen when kits are removed - virtual void cleanupKit(Kit *k); + void makePersistent(Kit *k) const; + void cleanupKit(Kit *k); bool isTemporaryKit(Kit *k) const; @@ -89,12 +89,30 @@ protected: using KitSetupFunction = std::function; ProjectExplorer::Kit *createTemporaryKit(const KitSetupFunction &setup) const; + // Handle temporary additions to Kits (Qt Versions, ToolChains, etc.) + using CleanupFunction = std::function; + using PersistFunction = std::function; + void useTemporaryKitInformation(Core::Id id, + CleanupFunction cleanup, PersistFunction persist); + void addTemporaryData(Core::Id id, const QVariant &cleanupData, Kit *k) const; + // Does *any* kit feature the requested data yet? + bool hasKitWithTemporaryData(Core::Id id, const QVariant &data) const; + private: - void markTemporary(Kit *k) const; + void markKitAsTemporary(Kit *k) const; + bool findTemporaryHandler(Core::Id id) const; const QString m_projectPath; mutable bool m_isUpdating = false; + class TemporaryInformationHandler { + public: + Core::Id id; + CleanupFunction cleanup; + PersistFunction persist; + }; + QList m_temporaryHandlers; + friend class UpdateGuard; }; diff --git a/src/plugins/projectexplorer/targetsetuppage.cpp b/src/plugins/projectexplorer/targetsetuppage.cpp index d9bf59a1c42..9ee60436c57 100644 --- a/src/plugins/projectexplorer/targetsetuppage.cpp +++ b/src/plugins/projectexplorer/targetsetuppage.cpp @@ -362,7 +362,7 @@ void TargetSetupPage::handleKitUpdate(Kit *k) return; if (m_importer) - m_importer->makePermanent(k); + m_importer->makePersistent(k); TargetSetupWidget *widget = m_widgets.value(k->id()); @@ -543,7 +543,7 @@ bool TargetSetupPage::setupProject(Project *project) Kit *k = widget->kit(); if (m_importer) - m_importer->makePermanent(k); + m_importer->makePersistent(k); toSetUp << widget->selectedBuildInfoList(); widget->clearKit(); } diff --git a/src/plugins/qtsupport/qtprojectimporter.cpp b/src/plugins/qtsupport/qtprojectimporter.cpp index 02368c3259d..112e4b06b68 100644 --- a/src/plugins/qtsupport/qtprojectimporter.cpp +++ b/src/plugins/qtsupport/qtprojectimporter.cpp @@ -35,6 +35,7 @@ #include #include +#include #include #include @@ -43,38 +44,11 @@ using namespace ProjectExplorer; namespace QtSupport { -const Core::Id QT_IS_TEMPORARY("Qt.TempQt"); - -static void cleanTemporaryVersion(BaseQtVersion *version) { - if (!version) - return; - - // count how many kits are using this version - const int qtId = version->uniqueId(); - const int users = Utils::count(KitManager::kits(), [qtId](Kit *k) { - return k->value(QT_IS_TEMPORARY, -1).toInt() == qtId; - }); - - if (users == 0) // Remove if no other kit is using it. (The Kit k is not in KitManager::kits() - QtVersionManager::removeVersion(version); -} - -void QtProjectImporter::makePermanent(Kit *k) const +QtProjectImporter::QtProjectImporter(const QString &path) : ProjectImporter(path) { - if (!isTemporaryKit(k)) - return; - - UpdateGuard guard(*this); - const int tempId = k->value(QT_IS_TEMPORARY, -1).toInt(); - k->removeKeySilently(QT_IS_TEMPORARY); - const int qtId = QtKitInformation::qtVersionId(k); - if (tempId != qtId) - cleanTemporaryVersion(QtVersionManager::version(tempId)); - - foreach (Kit *kit, KitManager::kits()) - if (kit->value(QT_IS_TEMPORARY, -1).toInt() == tempId) - kit->removeKeySilently(QT_IS_TEMPORARY); - ProjectImporter::makePermanent(k); + useTemporaryKitInformation(QtKitInformation::id(), + [this](Kit *k, const QVariantList &vl) { cleanupTemporaryQt(k, vl); }, + [this](Kit *k, const QVariantList &vl) { persistTemporaryQt(k, vl); }); } QtProjectImporter::QtVersionData @@ -92,9 +66,7 @@ QtProjectImporter::findOrCreateQtVersion(const Utils::FileName &qmakePath) const if (result.qt) { // Check if version is a temporary qt const int qtId = result.qt->uniqueId(); - result.isTemporary = Utils::anyOf(KitManager::kits(), [&qtId](Kit *k) { - return k->value(QT_IS_TEMPORARY, -1).toInt() == qtId; - }); + result.isTemporary = hasKitWithTemporaryData(QtKitInformation::id(), qtId); return result; } @@ -111,17 +83,46 @@ QtProjectImporter::findOrCreateQtVersion(const Utils::FileName &qmakePath) const } Kit *QtProjectImporter::createTemporaryKit(const QtVersionData &versionData, - const ProjectImporter::KitSetupFunction &setup) const + const ProjectImporter::KitSetupFunction &additionalSetup) const { - return ProjectImporter::createTemporaryKit([&setup, &versionData](Kit *k) -> void { + return ProjectImporter::createTemporaryKit([&additionalSetup, &versionData, this](Kit *k) -> void { QtKitInformation::setQtVersion(k, versionData.qt); if (versionData.isTemporary) - k->setValue(QT_IS_TEMPORARY, versionData.qt->uniqueId()); + addTemporaryData(QtKitInformation::id(), versionData.qt->uniqueId(), k); k->setUnexpandedDisplayName(versionData.qt->displayName());; - setup(k); + additionalSetup(k); }); } +static BaseQtVersion *versionFromVariant(const QVariant &v) +{ + bool ok; + const int qtId = v.toInt(&ok); + QTC_ASSERT(ok, return nullptr); + return QtVersionManager::version(qtId); +} + +void QtProjectImporter::cleanupTemporaryQt(Kit *k, const QVariantList &vl) +{ + Q_UNUSED(k); + + QTC_ASSERT(vl.count() == 1, return); + BaseQtVersion *version = versionFromVariant(vl.at(0)); + QTC_ASSERT(version, return); + QtVersionManager::removeVersion(version); +} + +void QtProjectImporter::persistTemporaryQt(Kit *k, const QVariantList &vl) +{ + QTC_ASSERT(vl.count() == 1, return); + BaseQtVersion *tmpVersion = versionFromVariant(vl.at(0)); + BaseQtVersion *actualVersion = QtKitInformation::qtVersion(k); + + // User changed Kit away from temporary Qt that was set up: + if (tmpVersion && actualVersion != tmpVersion) + QtVersionManager::removeVersion(tmpVersion); +} + } // namespace QtSupport diff --git a/src/plugins/qtsupport/qtprojectimporter.h b/src/plugins/qtsupport/qtprojectimporter.h index a596c87cb52..681dac3efb7 100644 --- a/src/plugins/qtsupport/qtprojectimporter.h +++ b/src/plugins/qtsupport/qtprojectimporter.h @@ -41,9 +41,6 @@ class QTSUPPORT_EXPORT QtProjectImporter : public ProjectExplorer::ProjectImport public: QtProjectImporter(const QString &path); - void cleanupKit(ProjectExplorer::Kit *k) override; - void makePermanent(ProjectExplorer::Kit *k) const override; - class QtVersionData { public: @@ -55,6 +52,10 @@ protected: QtVersionData findOrCreateQtVersion(const Utils::FileName &qmakePath) const; ProjectExplorer::Kit *createTemporaryKit(const QtVersionData &versionData, const KitSetupFunction &setup) const; + +private: + void cleanupTemporaryQt(ProjectExplorer::Kit *k, const QVariantList &vl); + void persistTemporaryQt(ProjectExplorer::Kit *k, const QVariantList &vl); }; } // namespace QmakeProjectManager