From 0b85fc5aa0a9dd9ab9d2bd702c11ee5816b87aa3 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 11 Sep 2023 08:58:51 +0200 Subject: [PATCH] ProjectExplorer: reduce the perceived startup time ... by moving restoreKits to the delayed initialize phase. Change-Id: If72e41b64ee71f2917b3f7a317d9887afc6e29e8 Reviewed-by: Eike Ziller --- .../cmakeprojectmanager/cmakekitaspect.cpp | 12 ++++-- .../coreplugin/dialogs/settingsdialog.cpp | 10 +++++ src/plugins/debugger/debuggerplugin.cpp | 11 +++-- .../debugger/unstartedappwatcherdialog.cpp | 2 +- src/plugins/help/helpplugin.cpp | 9 ++++- src/plugins/projectexplorer/kitmanager.cpp | 40 ++++++++++++++++++- src/plugins/projectexplorer/kitmanager.h | 2 + .../projectexplorer/kitoptionspage.cpp | 10 +++-- src/plugins/projectexplorer/project.cpp | 10 ++++- .../projectexplorer/projectexplorer.cpp | 12 ++---- src/plugins/projectexplorer/projectexplorer.h | 2 +- .../projectexplorer/toolchainmanager.cpp | 5 +++ src/plugins/qtsupport/externaleditors.cpp | 4 ++ 13 files changed, 103 insertions(+), 26 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakekitaspect.cpp b/src/plugins/cmakeprojectmanager/cmakekitaspect.cpp index 19f7c463610..720d2e5f156 100644 --- a/src/plugins/cmakeprojectmanager/cmakekitaspect.cpp +++ b/src/plugins/cmakeprojectmanager/cmakekitaspect.cpp @@ -224,13 +224,19 @@ CMakeKitAspectFactory::CMakeKitAspectFactory() "This setting is ignored when using other build systems.")); setPriority(20000); + auto updateKits = [this] { + if (KitManager::isLoaded()) { + for (Kit *k : KitManager::kits()) + fix(k); + } + }; + //make sure the default value is set if a selected CMake is removed - connect(CMakeToolManager::instance(), &CMakeToolManager::cmakeRemoved, - this, [this] { for (Kit *k : KitManager::kits()) fix(k); }); + connect(CMakeToolManager::instance(), &CMakeToolManager::cmakeRemoved, this, updateKits); //make sure the default value is set if a new default CMake is set connect(CMakeToolManager::instance(), &CMakeToolManager::defaultCMakeChanged, - this, [this] { for (Kit *k : KitManager::kits()) fix(k); }); + this, updateKits); } Id CMakeKitAspect::id() diff --git a/src/plugins/coreplugin/dialogs/settingsdialog.cpp b/src/plugins/coreplugin/dialogs/settingsdialog.cpp index 79cd816e368..9d610ddd135 100644 --- a/src/plugins/coreplugin/dialogs/settingsdialog.cpp +++ b/src/plugins/coreplugin/dialogs/settingsdialog.cpp @@ -37,6 +37,8 @@ #include #include +#include + const int kInitialWidth = 750; const int kInitialHeight = 450; const int kMaxMinimumWidth = 250; @@ -800,6 +802,14 @@ bool SettingsDialog::execDialog() bool executeSettingsDialog(QWidget *parent, Id initialPage) { + if (!ExtensionSystem::PluginManager::isInitializationDone()) { + QObject::connect(ExtensionSystem::PluginManager::instance(), + &ExtensionSystem::PluginManager::initializationDone, + parent, + [parent, initialPage]() { executeSettingsDialog(parent, initialPage); }); + return false; + } + // Make sure all wizards are there when the user might access the keyboard shortcuts: (void) IWizardFactory::allWizardFactories(); diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 04c78ca205c..f2c8c59de2f 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -1316,6 +1316,9 @@ static Kit *guessKitFromAbis(const Abis &abis) { Kit *kit = nullptr; + if (!KitManager::waitForLoaded()) + return kit; + // Try to find a kit via ABI. if (!abis.isEmpty()) { // Try exact abis. @@ -1376,9 +1379,11 @@ bool DebuggerPluginPrivate::parseArgument(QStringList::const_iterator &it, return false; } } else if (key == "kit") { - kit = KitManager::kit(Id::fromString(val)); - if (!kit) - kit = KitManager::kit(Utils::equal(&Kit::displayName, val)); + if (KitManager::waitForLoaded()) { + kit = KitManager::kit(Id::fromString(val)); + if (!kit) + kit = KitManager::kit(Utils::equal(&Kit::displayName, val)); + } } else if (key == "server") { startMode = AttachToRemoteServer; remoteChannel = val; diff --git a/src/plugins/debugger/unstartedappwatcherdialog.cpp b/src/plugins/debugger/unstartedappwatcherdialog.cpp index 95926afcbcf..e120571839e 100644 --- a/src/plugins/debugger/unstartedappwatcherdialog.cpp +++ b/src/plugins/debugger/unstartedappwatcherdialog.cpp @@ -84,7 +84,7 @@ UnstartedAppWatcherDialog::UnstartedAppWatcherDialog(QWidget *parent) if (kit) m_kitChooser->setCurrentKitId(kit->id()); - else if (KitManager::defaultKit()) + else if (KitManager::waitForLoaded() && KitManager::defaultKit()) m_kitChooser->setCurrentKitId(KitManager::defaultKit()->id()); auto pathLayout = new QHBoxLayout; diff --git a/src/plugins/help/helpplugin.cpp b/src/plugins/help/helpplugin.cpp index 346b2858d22..2879d57dd5e 100644 --- a/src/plugins/help/helpplugin.cpp +++ b/src/plugins/help/helpplugin.cpp @@ -38,6 +38,8 @@ #include +#include + #include #include @@ -283,7 +285,12 @@ void HelpPlugin::extensionsInitialized() bool HelpPlugin::delayedInitialize() { - HelpManager::setupHelpManager(); + if (ProjectExplorer::KitManager::isLoaded()) { + HelpManager::setupHelpManager(); + } else { + connect(ProjectExplorer::KitManager::instance(), &ProjectExplorer::KitManager::kitsLoaded, + this, &HelpManager::setupHelpManager); + } return true; } diff --git a/src/plugins/projectexplorer/kitmanager.cpp b/src/plugins/projectexplorer/kitmanager.cpp index 51529353e2e..d206234cbd1 100644 --- a/src/plugins/projectexplorer/kitmanager.cpp +++ b/src/plugins/projectexplorer/kitmanager.cpp @@ -13,6 +13,7 @@ #include "toolchainmanager.h" #include +#include #include #include @@ -421,10 +422,10 @@ void KitManager::restoreKits() if (!k) k = Utils::findOrDefault(resultList, &Kit::isValid); std::swap(resultList, d->m_kitList); + d->m_initialized = true; setDefaultKit(k); d->m_writer = std::make_unique(settingsFileName(), "QtCreatorProfiles"); - d->m_initialized = true; kitAspectFactoriesStorage().onKitsLoaded(); @@ -467,6 +468,33 @@ bool KitManager::isLoaded() return d->m_initialized; } +bool KitManager::waitForLoaded(const int timeout) +{ + if (isLoaded()) + return true; + showLoadingProgress(); + QElapsedTimer timer; + timer.start(); + while (!isLoaded() && !timer.hasExpired(timeout)) + QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); + return KitManager::isLoaded(); +} + +void KitManager::showLoadingProgress() +{ + if (isLoaded()) + return; + static QFutureInterface futureInterface; + if (futureInterface.isRunning()) + return; + futureInterface.reportStarted(); + Core::ProgressManager::addTimedTask(futureInterface.future(), + Tr::tr("Loading Kits"), + "LoadingKitsProgress", + 5); + connect(instance(), &KitManager::kitsLoaded, []() { futureInterface.reportFinished(); }); +} + void KitManager::setBinaryForKit(const FilePath &binary) { QTC_ASSERT(d, return); @@ -475,6 +503,7 @@ void KitManager::setBinaryForKit(const FilePath &binary) const QList KitManager::sortedKits() { + QTC_ASSERT(KitManager::isLoaded(), return {}); // This method was added to delay the sorting of kits as long as possible. // Since the displayName can contain variables it can be costly (e.g. involve // calling executables to find version information, etc.) to call that @@ -548,6 +577,7 @@ static KitList restoreKitsHelper(const FilePath &fileName) const QList KitManager::kits() { + QTC_ASSERT(KitManager::isLoaded(), return {}); return Utils::toRawPointer(d->m_kitList); } @@ -556,6 +586,7 @@ Kit *KitManager::kit(Id id) if (!id.isValid()) return nullptr; + QTC_ASSERT(KitManager::isLoaded(), return {}); return Utils::findOrDefault(d->m_kitList, Utils::equal(&Kit::id, id)); } @@ -566,6 +597,7 @@ Kit *KitManager::kit(const Kit::Predicate &predicate) Kit *KitManager::defaultKit() { + QTC_ASSERT(KitManager::isLoaded(), return {}); return d->m_defaultKit; } @@ -597,7 +629,7 @@ void KitManager::notifyAboutUpdate(Kit *k) Kit *KitManager::registerKit(const std::function &init, Utils::Id id) { - QTC_ASSERT(isLoaded(), return nullptr); + QTC_ASSERT(isLoaded(), return {}); auto k = std::make_unique(id); QTC_ASSERT(k->id().isValid(), return nullptr); @@ -620,6 +652,8 @@ Kit *KitManager::registerKit(const std::function &init, Utils::Id void KitManager::deregisterKit(Kit *k) { + QTC_ASSERT(KitManager::isLoaded(), return); + if (!k || !Utils::contains(d->m_kitList, k)) return; auto taken = Utils::take(d->m_kitList, k); @@ -632,6 +666,8 @@ void KitManager::deregisterKit(Kit *k) void KitManager::setDefaultKit(Kit *k) { + QTC_ASSERT(KitManager::isLoaded(), return); + if (defaultKit() == k) return; if (k && !Utils::contains(d->m_kitList, k)) diff --git a/src/plugins/projectexplorer/kitmanager.h b/src/plugins/projectexplorer/kitmanager.h index a71538cef9c..377f96498ce 100644 --- a/src/plugins/projectexplorer/kitmanager.h +++ b/src/plugins/projectexplorer/kitmanager.h @@ -155,6 +155,8 @@ public: static void saveKits(); static bool isLoaded(); + static bool waitForLoaded(const int timeout = 60 * 1000); // timeout in ms + static void showLoadingProgress(); signals: void kitAdded(ProjectExplorer::Kit *); diff --git a/src/plugins/projectexplorer/kitoptionspage.cpp b/src/plugins/projectexplorer/kitoptionspage.cpp index 14098e98320..62c119a46a2 100644 --- a/src/plugins/projectexplorer/kitoptionspage.cpp +++ b/src/plugins/projectexplorer/kitoptionspage.cpp @@ -197,6 +197,7 @@ signals: void kitStateChanged(); private: + void initializeFromKitManager(); void addKit(Kit *k); void updateKit(Kit *k); void removeKit(Kit *k); @@ -227,10 +228,11 @@ KitModel::KitModel(QBoxLayout *parentLayout, QObject *parent) rootItem()->appendChild(m_autoRoot); rootItem()->appendChild(m_manualRoot); - for (Kit *k : KitManager::sortedKits()) - addKit(k); - - changeDefaultKit(); + if (KitManager::isLoaded()) { + for (Kit *k : KitManager::sortedKits()) + addKit(k); + changeDefaultKit(); + } connect(KitManager::instance(), &KitManager::kitAdded, this, &KitModel::addKit); diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp index 52a4b8e0a61..4333680bb76 100644 --- a/src/plugins/projectexplorer/project.cpp +++ b/src/plugins/projectexplorer/project.cpp @@ -24,13 +24,13 @@ #include "toolchainmanager.h" #include "userfileaccessor.h" -#include #include +#include #include #include +#include #include #include -#include #include #include @@ -643,6 +643,12 @@ void Project::saveSettings() Project::RestoreResult Project::restoreSettings(QString *errorMessage) { + if (!KitManager::waitForLoaded()) { + if (errorMessage) + *errorMessage = Tr::tr("Could not load kits in a reasonable amount of time."); + return RestoreResult::Error; + } + if (!d->m_accessor) d->m_accessor = std::make_unique(this); Store map(d->m_accessor->restoreSettings(ICore::dialogParent())); diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 64229ce4ccc..c1f90598218 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -2121,20 +2121,15 @@ void ProjectExplorerPlugin::extensionsInitialized() // Load devices immediately, as other plugins might want to use them DeviceManager::instance()->load(); - - // delay restoring kits until UI is shown for improved perceived startup performance - QTimer::singleShot(0, this, &ProjectExplorerPlugin::restoreKits); } -void ProjectExplorerPlugin::restoreKits() +bool ProjectExplorerPlugin::delayedInitialize() { NANOTRACE_SCOPE("ProjectExplorer", "ProjectExplorerPlugin::restoreKits"); ExtraAbi::load(); // Load this before Toolchains! ToolChainManager::restoreToolChains(); KitManager::restoreKits(); - // restoring startup session is supposed to be done as a result of ICore::coreOpened, - // and that is supposed to happen after restoring kits: - QTC_CHECK(!SessionManager::isStartupSessionRestored()); + return true; } void ProjectExplorerPluginPrivate::updateRunWithoutDeployMenu() @@ -2379,8 +2374,7 @@ ProjectExplorerPlugin::OpenProjectResult ProjectExplorerPlugin::openProjects(con dd->updateActions(); const bool switchToProjectsMode = Utils::anyOf(openedPro, &Project::needsConfiguration); - const bool switchToEditMode = Utils::allOf(openedPro, - [](Project *p) { return p->isEditModePreferred(); }); + const bool switchToEditMode = Utils::allOf(openedPro, &Project::isEditModePreferred); if (!openedPro.isEmpty()) { if (switchToProjectsMode) ModeManager::activateMode(Constants::MODE_SESSION); diff --git a/src/plugins/projectexplorer/projectexplorer.h b/src/plugins/projectexplorer/projectexplorer.h index 33dcbe2ad17..eec4fae8601 100644 --- a/src/plugins/projectexplorer/projectexplorer.h +++ b/src/plugins/projectexplorer/projectexplorer.h @@ -106,7 +106,7 @@ public: //PluginInterface bool initialize(const QStringList &arguments, QString *errorMessage) override; void extensionsInitialized() override; - void restoreKits(); + bool delayedInitialize() override; ShutdownFlag aboutToShutdown() override; static void setProjectExplorerSettings(const ProjectExplorerSettings &pes); diff --git a/src/plugins/projectexplorer/toolchainmanager.cpp b/src/plugins/projectexplorer/toolchainmanager.cpp index dd14b827468..3c90d590a39 100644 --- a/src/plugins/projectexplorer/toolchainmanager.cpp +++ b/src/plugins/projectexplorer/toolchainmanager.cpp @@ -129,6 +129,7 @@ void ToolChainManager::saveToolChains() const Toolchains &ToolChainManager::toolchains() { + QTC_CHECK(d->m_loaded); return d->m_toolChains; } @@ -140,11 +141,13 @@ Toolchains ToolChainManager::toolchains(const ToolChain::Predicate &predicate) ToolChain *ToolChainManager::toolChain(const ToolChain::Predicate &predicate) { + QTC_CHECK(d->m_loaded); return Utils::findOrDefault(d->m_toolChains, predicate); } Toolchains ToolChainManager::findToolChains(const Abi &abi) { + QTC_CHECK(d->m_loaded); Toolchains result; for (ToolChain *tc : std::as_const(d->m_toolChains)) { bool isCompatible = Utils::anyOf(tc->supportedAbis(), [abi](const Abi &supportedAbi) { @@ -159,6 +162,7 @@ Toolchains ToolChainManager::findToolChains(const Abi &abi) ToolChain *ToolChainManager::findToolChain(const QByteArray &id) { + QTC_CHECK(d->m_loaded); if (id.isEmpty()) return nullptr; @@ -214,6 +218,7 @@ bool ToolChainManager::registerToolChain(ToolChain *tc) void ToolChainManager::deregisterToolChain(ToolChain *tc) { + QTC_CHECK(d->m_loaded); if (!tc || !d->m_toolChains.contains(tc)) return; d->m_toolChains.removeOne(tc); diff --git a/src/plugins/qtsupport/externaleditors.cpp b/src/plugins/qtsupport/externaleditors.cpp index 257347fa6bd..36abc53dbdf 100644 --- a/src/plugins/qtsupport/externaleditors.cpp +++ b/src/plugins/qtsupport/externaleditors.cpp @@ -179,6 +179,10 @@ static bool getEditorLaunchData(const CommandForQtVersion &commandForQtVersion, // - default kit // - any other kit // As fallback check PATH + if (!KitManager::waitForLoaded()) { + *errorMessage = Tr::tr("Could not load kits in a reasonable amount of time."); + return false; + } data->workingDirectory.clear(); QVector qtVersionsToCheck; // deduplicated after being filled if (const Project *project = ProjectManager::projectForFile(filePath)) {