forked from qt-creator/qt-creator
ExtensionSystem: Allow opt-in plugin loading without restart
Change-Id: I682e51d047c43ff5bf4647ef7e015222707f3204 Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io> Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
@@ -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,6 +1623,7 @@ void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destSt
|
||||
break;
|
||||
}
|
||||
// check if dependencies have loaded without error
|
||||
if (!spec->isSoftLoadable()) {
|
||||
const QHash<PluginDependency, PluginSpec *> deps = spec->dependencySpecs();
|
||||
for (auto it = deps.cbegin(), end = deps.cend(); it != end; ++it) {
|
||||
if (it.key().type != PluginDependency::Required)
|
||||
@@ -1629,6 +1637,7 @@ void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destSt
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (destState) {
|
||||
case PluginSpec::Loaded: {
|
||||
NANOTRACE_SCOPE(specName, specName + "::load");
|
||||
|
||||
@@ -68,6 +68,7 @@ public:
|
||||
// Plugin operations
|
||||
static QVector<PluginSpec *> loadQueue();
|
||||
static void loadPlugins();
|
||||
static void loadPlugin(PluginSpec *);
|
||||
static QStringList pluginPaths();
|
||||
static void setPluginPaths(const QStringList &paths);
|
||||
static QString pluginIID();
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -100,6 +100,7 @@ public:
|
||||
bool isEnabledIndirectly() const;
|
||||
bool isForceEnabled() const;
|
||||
bool isForceDisabled() const;
|
||||
bool isSoftLoadable() const;
|
||||
QVector<PluginDependency> dependencies() const;
|
||||
QJsonObject metaData() const;
|
||||
const PerformanceData &performanceData() const;
|
||||
|
||||
@@ -45,6 +45,7 @@ public:
|
||||
void setEnabledByDefault(bool value);
|
||||
void setForceEnabled(bool value);
|
||||
void setForceDisabled(bool value);
|
||||
void setSoftLoadable(bool value);
|
||||
|
||||
std::optional<QPluginLoader> loader;
|
||||
std::optional<QStaticPlugin> staticPlugin;
|
||||
@@ -69,6 +70,7 @@ public:
|
||||
bool enabledIndirectly = false;
|
||||
bool forceEnabled = false;
|
||||
bool forceDisabled = false;
|
||||
bool softLoadable = false;
|
||||
|
||||
QString location;
|
||||
QString filePath;
|
||||
|
||||
@@ -237,9 +237,7 @@ public:
|
||||
if (column == LoadedColumn && role == Qt::CheckStateRole) {
|
||||
const QVector<PluginSpec *> affectedPlugins
|
||||
= Utils::filtered(m_plugins, [](PluginSpec *spec) { return !spec->isRequired(); });
|
||||
if (m_view->setPluginsEnabled(Utils::transform<QSet>(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<PluginSpec *> &plugins, bool enabl
|
||||
spec->d->setEnabledBySettings(enable);
|
||||
item->updateColumn(LoadedColumn);
|
||||
item->parent()->updateColumn(LoadedColumn);
|
||||
emit pluginSettingsChanged(spec);
|
||||
}
|
||||
emit pluginsChanged(affectedPlugins, enable);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include <utils/treemodel.h>
|
||||
|
||||
#include <QSet>
|
||||
#include <QWidget>
|
||||
|
||||
#include <unordered_map>
|
||||
@@ -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<ExtensionSystem::PluginSpec *> &spec, bool enabled);
|
||||
|
||||
private:
|
||||
PluginSpec *pluginForIndex(const QModelIndex &index) const;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <extensionsystem/pluginspec.h>
|
||||
#include <extensionsystem/pluginview.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/fancylineedit.h>
|
||||
#include <utils/layoutbuilder.h>
|
||||
|
||||
@@ -21,6 +22,7 @@
|
||||
#include <QDialogButtonBox>
|
||||
#include <QPushButton>
|
||||
|
||||
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] {
|
||||
connect(m_view, &ExtensionSystem::PluginView::pluginsChanged,
|
||||
this, [this](const QSet<PluginSpec *> &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."));
|
||||
|
||||
@@ -38,6 +38,7 @@ private:
|
||||
QPushButton *m_errorDetailsButton;
|
||||
QPushButton *m_installButton;
|
||||
bool m_isRestartRequired = false;
|
||||
QSet<ExtensionSystem::PluginSpec *> m_softLoad;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
Reference in New Issue
Block a user