diff --git a/src/libs/extensionsystem/pluginmanager.cpp b/src/libs/extensionsystem/pluginmanager.cpp index 1f86693f907..7114813bd71 100644 --- a/src/libs/extensionsystem/pluginmanager.cpp +++ b/src/libs/extensionsystem/pluginmanager.cpp @@ -322,6 +322,13 @@ void PluginManager::loadPlugins() d->loadPlugins(); } +void PluginManager::loadPlugin(PluginSpec *spec) +{ + d->loadPlugin(spec, PluginSpec::Loaded); + d->loadPlugin(spec, PluginSpec::Initialized); + d->loadPlugin(spec, PluginSpec::Running); +} + /*! Returns \c true if any plugin has errors even though it is enabled. Most useful to call after loadPlugins(). @@ -1616,17 +1623,19 @@ void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destSt break; } // check if dependencies have loaded without error - const QHash deps = spec->dependencySpecs(); - for (auto it = deps.cbegin(), end = deps.cend(); it != end; ++it) { - if (it.key().type != PluginDependency::Required) - continue; - PluginSpec *depSpec = it.value(); - if (depSpec->state() != destState) { - spec->d->hasError = true; - spec->d->errorString = - Tr::tr("Cannot load plugin because dependency failed to load: %1(%2)\nReason: %3") - .arg(depSpec->name(), depSpec->version(), depSpec->errorString()); - return; + if (!spec->isSoftLoadable()) { + const QHash deps = spec->dependencySpecs(); + for (auto it = deps.cbegin(), end = deps.cend(); it != end; ++it) { + if (it.key().type != PluginDependency::Required) + continue; + PluginSpec *depSpec = it.value(); + if (depSpec->state() != destState) { + spec->d->hasError = true; + spec->d->errorString = + Tr::tr("Cannot load plugin because dependency failed to load: %1(%2)\nReason: %3") + .arg(depSpec->name(), depSpec->version(), depSpec->errorString()); + return; + } } } switch (destState) { diff --git a/src/libs/extensionsystem/pluginmanager.h b/src/libs/extensionsystem/pluginmanager.h index e7c6a315259..97bb7f26473 100644 --- a/src/libs/extensionsystem/pluginmanager.h +++ b/src/libs/extensionsystem/pluginmanager.h @@ -68,6 +68,7 @@ public: // Plugin operations static QVector loadQueue(); static void loadPlugins(); + static void loadPlugin(PluginSpec *); static QStringList pluginPaths(); static void setPluginPaths(const QStringList &paths); static QString pluginIID(); diff --git a/src/libs/extensionsystem/pluginspec.cpp b/src/libs/extensionsystem/pluginspec.cpp index bbc4e3541c0..cd26e814647 100644 --- a/src/libs/extensionsystem/pluginspec.cpp +++ b/src/libs/extensionsystem/pluginspec.cpp @@ -386,6 +386,11 @@ bool PluginSpec::isForceDisabled() const return d->forceDisabled; } +bool PluginSpec::isSoftLoadable() const +{ + return d->softLoadable; +} + /*! The plugin dependencies. This is valid after the PluginSpec::Read state is reached. */ @@ -570,6 +575,7 @@ namespace { const char PLUGIN_REQUIRED[] = "Required"; const char PLUGIN_EXPERIMENTAL[] = "Experimental"; const char PLUGIN_DISABLED_BY_DEFAULT[] = "DisabledByDefault"; + const char PLUGIN_SOFTLOADABLE[] = "SoftLoadable"; const char VENDOR[] = "Vendor"; const char COPYRIGHT[] = "Copyright"; const char LICENSE[] = "License"; @@ -683,6 +689,11 @@ void PluginSpecPrivate::setForceDisabled(bool value) forceDisabled = value; } +void PluginSpecPrivate::setSoftLoadable(bool value) +{ + softLoadable = value; +} + /*! \internal */ @@ -796,6 +807,12 @@ bool PluginSpecPrivate::readMetaData(const QJsonObject &pluginMetaData) enabledByDefault = false; enabledBySettings = enabledByDefault; + value = metaData.value(QLatin1String(PLUGIN_SOFTLOADABLE)); + if (!value.isUndefined() && !value.isBool()) + return reportError(msgValueIsNotABool(PLUGIN_SOFTLOADABLE)); + softLoadable = value.toBool(false); + qCDebug(pluginLog) << "softLoadable =" << softLoadable; + value = metaData.value(QLatin1String(VENDOR)); if (!value.isUndefined() && !value.isString()) return reportError(msgValueIsNotAString(VENDOR)); diff --git a/src/libs/extensionsystem/pluginspec.h b/src/libs/extensionsystem/pluginspec.h index 6030bc568e4..68cebae9b67 100644 --- a/src/libs/extensionsystem/pluginspec.h +++ b/src/libs/extensionsystem/pluginspec.h @@ -100,6 +100,7 @@ public: bool isEnabledIndirectly() const; bool isForceEnabled() const; bool isForceDisabled() const; + bool isSoftLoadable() const; QVector dependencies() const; QJsonObject metaData() const; const PerformanceData &performanceData() const; diff --git a/src/libs/extensionsystem/pluginspec_p.h b/src/libs/extensionsystem/pluginspec_p.h index f802902e53c..d171265b13c 100644 --- a/src/libs/extensionsystem/pluginspec_p.h +++ b/src/libs/extensionsystem/pluginspec_p.h @@ -45,6 +45,7 @@ public: void setEnabledByDefault(bool value); void setForceEnabled(bool value); void setForceDisabled(bool value); + void setSoftLoadable(bool value); std::optional loader; std::optional staticPlugin; @@ -69,6 +70,7 @@ public: bool enabledIndirectly = false; bool forceEnabled = false; bool forceDisabled = false; + bool softLoadable = false; QString location; QString filePath; diff --git a/src/libs/extensionsystem/pluginview.cpp b/src/libs/extensionsystem/pluginview.cpp index 71a8d3de764..ccb4d66362c 100644 --- a/src/libs/extensionsystem/pluginview.cpp +++ b/src/libs/extensionsystem/pluginview.cpp @@ -237,9 +237,7 @@ public: if (column == LoadedColumn && role == Qt::CheckStateRole) { const QVector affectedPlugins = Utils::filtered(m_plugins, [](PluginSpec *spec) { return !spec->isRequired(); }); - if (m_view->setPluginsEnabled(Utils::transform(affectedPlugins, - [](PluginSpec *s) { return s; }), - data.toBool())) { + if (m_view->setPluginsEnabled(toSet(affectedPlugins), data.toBool())) { update(); return true; } @@ -419,8 +417,8 @@ bool PluginView::setPluginsEnabled(const QSet &plugins, bool enabl spec->d->setEnabledBySettings(enable); item->updateColumn(LoadedColumn); item->parent()->updateColumn(LoadedColumn); - emit pluginSettingsChanged(spec); } + emit pluginsChanged(affectedPlugins, enable); return true; } diff --git a/src/libs/extensionsystem/pluginview.h b/src/libs/extensionsystem/pluginview.h index 09f1a5ce529..e241273ace3 100644 --- a/src/libs/extensionsystem/pluginview.h +++ b/src/libs/extensionsystem/pluginview.h @@ -7,6 +7,7 @@ #include +#include #include #include @@ -40,7 +41,7 @@ public: signals: void currentPluginChanged(ExtensionSystem::PluginSpec *spec); void pluginActivated(ExtensionSystem::PluginSpec *spec); - void pluginSettingsChanged(ExtensionSystem::PluginSpec *spec); + void pluginsChanged(const QSet &spec, bool enabled); private: PluginSpec *pluginForIndex(const QModelIndex &index) const; diff --git a/src/plugins/coreplugin/plugindialog.cpp b/src/plugins/coreplugin/plugindialog.cpp index 5e22463000c..5dcdcde9d88 100644 --- a/src/plugins/coreplugin/plugindialog.cpp +++ b/src/plugins/coreplugin/plugindialog.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -21,6 +22,7 @@ #include #include +using namespace ExtensionSystem; using namespace Utils; namespace Core { @@ -59,8 +61,16 @@ PluginDialog::PluginDialog(QWidget *parent) this, &PluginDialog::updateButtons); connect(m_view, &ExtensionSystem::PluginView::pluginActivated, this, &PluginDialog::openDetails); - connect(m_view, &ExtensionSystem::PluginView::pluginSettingsChanged, this, [this] { - m_isRestartRequired = true; + connect(m_view, &ExtensionSystem::PluginView::pluginsChanged, + this, [this](const QSet &plugins, bool enable) { + for (PluginSpec *plugin : plugins) { + if (enable && plugin->isSoftLoadable()) { + m_softLoad.insert(plugin); + } else { + m_softLoad.remove(plugin); // In case it was added, harmless otherwise. + m_isRestartRequired = true; + } + } }); connect(m_detailsButton, &QAbstractButton::clicked, this, [this] { openDetails(m_view->currentPlugin()); }); @@ -75,7 +85,11 @@ PluginDialog::PluginDialog(QWidget *parent) void PluginDialog::closeDialog() { - ExtensionSystem::PluginManager::writeSettings(); + PluginManager::writeSettings(); + + for (PluginSpec *plugin : m_softLoad) + PluginManager::loadPlugin(plugin); + if (m_isRestartRequired) { RestartDialog restartDialog(ICore::dialogParent(), Tr::tr("Plugin changes will take effect after restart.")); diff --git a/src/plugins/coreplugin/plugindialog.h b/src/plugins/coreplugin/plugindialog.h index 46633623410..e908e908bc4 100644 --- a/src/plugins/coreplugin/plugindialog.h +++ b/src/plugins/coreplugin/plugindialog.h @@ -38,6 +38,7 @@ private: QPushButton *m_errorDetailsButton; QPushButton *m_installButton; bool m_isRestartRequired = false; + QSet m_softLoad; }; } // namespace Internal