From 6ee74831f7d6e0ac15d42fe0fcb211321615d684 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Tue, 10 Nov 2020 21:44:38 +0100 Subject: Insert 'enabled' plugin if not present. --- src/settings.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/settings.cpp') diff --git a/src/settings.cpp b/src/settings.cpp index 54d32786..0f661bfb 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1296,6 +1296,11 @@ void PluginSettings::registerPlugin(IPlugin *plugin) .arg(setting.description) .arg(setting.defaultValue.toString()); } + + if (!m_PluginSettings.contains("enabled")) { + m_PluginSettings[plugin->name()]["enabled"] = true; + m_PluginDescriptions[plugin->name()]["enabled"] = QString(); + } } std::vector PluginSettings::plugins() const -- cgit v1.3.1 From 7a4f6d5344031db828f5dc2257c1d19f251e7f05 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Wed, 11 Nov 2020 13:39:53 +0100 Subject: Improve requirements handling. --- src/plugincontainer.cpp | 218 +++++++++++++++++++++++++++--------------- src/plugincontainer.h | 109 +++++++++++++++++---- src/settings.cpp | 17 +++- src/settingsdialog.ui | 10 ++ src/settingsdialogplugins.cpp | 97 ++++++++++++++++++- src/settingsdialogplugins.h | 7 ++ 6 files changed, 361 insertions(+), 97 deletions(-) (limited to 'src/settings.cpp') diff --git a/src/plugincontainer.cpp b/src/plugincontainer.cpp index 9045e457..021fe3c8 100644 --- a/src/plugincontainer.cpp +++ b/src/plugincontainer.cpp @@ -53,18 +53,108 @@ QStringList PluginContainer::pluginInterfaces() // PluginRequirementProxy -std::vector PluginRequirementProxy::problems() const +PluginRequirements::PluginRequirements(PluginContainer* pluginContainer, MOBase::IPlugin* plugin, IOrganizer* proxy, MOBase::IPluginProxy* pluginProxy) + : m_PluginContainer(pluginContainer) + , m_Plugin(plugin) + , m_PluginProxy(pluginProxy) + , m_Organizer(proxy) { - return m_Requirement->problems(m_Proxy); + for (auto* requirement : plugin->requirements()) { + m_Requirements.emplace_back(requirement); + } + + // TODO: + if (pluginProxy) { + m_Requirements.emplace_back(PluginRequirementFactory::pluginDependency(pluginProxy->name())); + } +} + +MOBase::IPluginProxy* PluginRequirements::proxy() const +{ + return m_PluginProxy; +} + +std::vector PluginRequirements::problems() const +{ + std::vector result; + for (auto& requirement : m_Requirements) { + for (auto p : requirement->problems(m_Organizer)) { + result.push_back(Problem(requirement.get(), p)); + } + } + return result; +} + +bool PluginRequirements::canEnable() const +{ + return problems().empty(); +} + +QStringList PluginRequirements::requiredGames() const +{ + // We look for a "GameDependencyRequirement" - There can be only one since otherwise + // it'd mean that the plugin requires two games at once. + for (auto& requirement : m_Requirements) { + if (auto* gdep = dynamic_cast(requirement.get())) { + return gdep->gameNames(); + } + } + + return {}; } -QString PluginRequirementProxy::description(unsigned int id) const + +std::vector PluginRequirements::requiredFor() const { - return m_Requirement->description(id); + std::vector required; + std::set visited; + requiredFor(required, visited); + return required; } -PluginRequirementProxy::PluginRequirementProxy(const MOBase::IPluginRequirement* requirement, OrganizerProxy* proxy) : - m_Requirement(requirement), m_Proxy(proxy) { } +void PluginRequirements::requiredFor(std::vector &required, std::set& visited) const +{ + // Handle cyclic dependencies. + if (visited.contains(m_Plugin)) { + return; + } + visited.insert(m_Plugin); + + + for (auto& [plugin, requirements] : m_PluginContainer->m_Requirements) { + + // If the plugin is not enabled, discard: + if (!m_PluginContainer->isEnabled(plugin)) { + continue; + } + + // Check the requirements: + for (auto& requirement : requirements.m_Requirements) { + + // We check for plugin dependency. Game dependency are not checked this way. + if (auto* pdep = dynamic_cast(requirement.get())) { + + // Check if at least one of the plugin in the requirements is enabled (except this + // one): + bool oneEnabled = false; + for (auto& pluginName : pdep->pluginNames()) { + if (pluginName != m_Plugin->name() && m_PluginContainer->isEnabled(pluginName)) { + oneEnabled = true; + break; + } + } + + // No plugin enabled found, so the plugin requires this plugin: + if (!oneEnabled) { + required.push_back(plugin); + requirements.requiredFor(required, visited); + break; + } + } + } + } +} + // PluginContainer PluginContainer::PluginContainer(OrganizerCore *organizer) @@ -186,7 +276,7 @@ QObject* PluginContainer::as_qobject(MOBase::IPlugin* plugin) const return *it; } -bool PluginContainer::initPlugin(IPlugin *plugin) +bool PluginContainer::initPlugin(IPlugin *plugin, IPluginProxy *pluginProxy) { // when MO has no instance loaded, init() is not called on plugins, except // for proxy plugins, where init() is called with a null IOrganizer @@ -199,63 +289,34 @@ bool PluginContainer::initPlugin(IPlugin *plugin) return false; } + OrganizerProxy* proxy = nullptr; if (m_Organizer) { - auto* proxy = new OrganizerProxy(m_Organizer, this, plugin); - m_Proxies[plugin] = proxy; - - // Create requirements before init() in case a plugin use - // IOrganizer::isPluginEnabled on himself during init(). - m_Requirements.emplace(plugin, 0); - - if (!plugin->init(proxy)) { - log::warn("plugin failed to initialize"); - return false; - } - - for (auto* requirement : plugin->requirements()) { - m_Requirements[plugin].emplace_back(requirement); - } + proxy = new OrganizerProxy(m_Organizer, this, plugin); } - return true; -} + // Check if it is a proxy plugin: + bool isProxy = dynamic_cast(plugin); -bool PluginContainer::initProxyPlugin(IPlugin *plugin) -{ - // see initPlugin() above for info - - if (plugin == nullptr) { - return false; + if (!m_Organizer && !isProxy) { + return true; } - OrganizerProxy* proxy = nullptr; - if (m_Organizer) { - proxy = new OrganizerProxy(m_Organizer, this, plugin); - m_Proxies[plugin] = proxy; - } - - // Create requirements before init() in case a plugin use - // IOrganizer::isPluginEnabled on himself during init(). - m_Requirements.emplace(plugin, 0); if (!plugin->init(proxy)) { - log::warn("proxy plugin failed to initialize"); + log::warn("plugin failed to initialize"); return false; } - for (auto* requirement : plugin->requirements()) { - m_Requirements[plugin].emplace_back(requirement); - } + m_Requirements.emplace(plugin, PluginRequirements(this, plugin, proxy, pluginProxy)); return true; } - void PluginContainer::registerGame(IPluginGame *game) { m_SupportedGames.insert({ game->gameName(), game }); } -bool PluginContainer::registerPlugin(QObject *plugin, const QString &fileName) +bool PluginContainer::registerPlugin(QObject *plugin, const QString &fileName, MOBase::IPluginProxy* pluginProxy) { // Storing the original QObject* is a bit of a hack as I couldn't figure out any // way to cast directly between IPlugin* and IPluginDiagnose* @@ -294,34 +355,32 @@ bool PluginContainer::registerPlugin(QObject *plugin, const QString &fileName) } { // mod page plugin IPluginModPage *modPage = qobject_cast(plugin); - if (initPlugin(modPage)) { + if (initPlugin(modPage, pluginProxy)) { bf::at_key(m_Plugins).push_back(modPage); return true; } } { // game plugin IPluginGame *game = qobject_cast(plugin); - if (game) { game->detectGame(); - } - - if (initPlugin(game)) { - bf::at_key(m_Plugins).push_back(game); - registerGame(game); - return true; + if (initPlugin(game, pluginProxy)) { + bf::at_key(m_Plugins).push_back(game); + registerGame(game); + return true; + } } } { // tool plugins IPluginTool *tool = qobject_cast(plugin); - if (initPlugin(tool)) { + if (initPlugin(tool, pluginProxy)) { bf::at_key(m_Plugins).push_back(tool); return true; } } { // installer plugins IPluginInstaller *installer = qobject_cast(plugin); - if (initPlugin(installer)) { + if (initPlugin(installer, pluginProxy)) { bf::at_key(m_Plugins).push_back(installer); if (m_Organizer) { m_Organizer->installationManager()->registerInstaller(installer); @@ -331,7 +390,7 @@ bool PluginContainer::registerPlugin(QObject *plugin, const QString &fileName) } { // preview plugins IPluginPreview *preview = qobject_cast(plugin); - if (initPlugin(preview)) { + if (initPlugin(preview, pluginProxy)) { bf::at_key(m_Plugins).push_back(preview); m_PreviewGenerator.registerPlugin(preview); return true; @@ -339,7 +398,7 @@ bool PluginContainer::registerPlugin(QObject *plugin, const QString &fileName) } { // proxy plugins IPluginProxy *proxy = qobject_cast(plugin); - if (initProxyPlugin(proxy)) { + if (initPlugin(proxy, pluginProxy)) { bf::at_key(m_Plugins).push_back(proxy); QStringList pluginNames = proxy->pluginList( QCoreApplication::applicationDirPath() + "/" + ToQString(AppConfig::pluginPath())); @@ -349,7 +408,7 @@ bool PluginContainer::registerPlugin(QObject *plugin, const QString &fileName) QList matchingPlugins = proxy->instantiate(pluginName); for (QObject *proxiedPlugin : matchingPlugins) { if (proxiedPlugin != nullptr) { - if (registerPlugin(proxiedPlugin, pluginName)) { + if (registerPlugin(proxiedPlugin, pluginName, proxy)) { log::debug("loaded plugin \"{}\"", QFileInfo(pluginName).fileName()); } else { @@ -371,7 +430,7 @@ bool PluginContainer::registerPlugin(QObject *plugin, const QString &fileName) { // dummy plugins // only initialize these, no processing otherwise IPlugin *dummy = qobject_cast(plugin); - if (initPlugin(dummy)) { + if (initPlugin(dummy, pluginProxy)) { bf::at_key(m_Plugins).push_back(dummy); return true; } @@ -419,6 +478,14 @@ void PluginContainer::unloadPlugins() } } +IPlugin* PluginContainer::managedGame() const +{ + // TODO: This const_cast is safe but ugly. Most methods require a IPlugin*, so + // returning a const-version if painful. This should be fixed by making methods accept + // a const IPlugin* instead, but there are a few tricks with qobject_cast and const. + return const_cast(m_Organizer->managedGame()); +} + bool PluginContainer::isEnabled(IPlugin* plugin) const { // Check if it's a game plugin: @@ -431,15 +498,21 @@ bool PluginContainer::isEnabled(IPlugin* plugin) const return false; } - // Check the requirements: - auto* proxy = m_Proxies.at(plugin); - for (auto& requirement : m_Requirements.at(plugin)) { - if (!requirement->problems(proxy).empty()) { - return false; + // Check the requirements (if a plugin checks in init(), the requirements have + // not been computed yet): + auto it = m_Requirements.find(plugin); + + return it == std::end(m_Requirements) ? true : it->second.canEnable(); +} + +void PluginContainer::setEnabled(MOBase::IPlugin* plugin, bool enable, bool dependencies) +{ + if (!enable && dependencies) { + for (auto* p : requirements(plugin).requiredFor()) { + setEnabled(p, false, false); // No need to "recurse" here since requiredFor already does it. } } - - return true; + m_Organizer->setPersistent(plugin->name(), "enabled", enable, true); } MOBase::IPlugin* PluginContainer::plugin(QString const& pluginName) const @@ -485,14 +558,9 @@ bool PluginContainer::isEnabled(MOBase::IPluginFileMapper* mapper) const { return p ? isEnabled(p) : false; } -std::vector PluginContainer::requirements(IPlugin* plugin) const +const PluginRequirements& PluginContainer::requirements(IPlugin* plugin) const { - auto* proxy = m_Proxies.at(plugin); - std::vector proxies; - for (auto& requirement : m_Requirements.at(plugin)) { - proxies.push_back(PluginRequirementProxy(requirement.get(), proxy)); - } - return proxies; + return m_Requirements.at(plugin); } IPluginGame *PluginContainer::managedGame(const QString &name) const @@ -517,7 +585,7 @@ void PluginContainer::loadPlugins() unloadPlugins(); for (QObject *plugin : QPluginLoader::staticInstances()) { - registerPlugin(plugin, ""); + registerPlugin(plugin, "", nullptr); } QFile loadCheck; @@ -613,7 +681,7 @@ void PluginContainer::loadPlugins() "failed to load plugin {}: {}", pluginName, pluginLoader->errorString()); } else { - if (registerPlugin(pluginLoader->instance(), pluginName)) { + if (registerPlugin(pluginLoader->instance(), pluginName, nullptr)) { log::debug("loaded plugin \"{}\"", QFileInfo(pluginName).fileName()); m_PluginLoaders.push_back(pluginLoader.release()); } else { diff --git a/src/plugincontainer.h b/src/plugincontainer.h index 26ad2046..cd1d03ca 100644 --- a/src/plugincontainer.h +++ b/src/plugincontainer.h @@ -27,24 +27,77 @@ class IUserInterface; class OrganizerProxy; +/** + * @brief Class that wrap multiple requirements for a plugin together. THis + * class owns the requirements. + */ +class PluginRequirements { +public: + + // Small intermediate class. + struct Problem { + public: + + QString description() const { return m_Requirement->description(m_Id); } + + + private: + Problem(const MOBase::IPluginRequirement* requirement, unsigned int id) : + m_Requirement(requirement), m_Id(id) { } + + const MOBase::IPluginRequirement* m_Requirement; + unsigned int m_Id; + + friend class PluginRequirements; + }; -// Small class that allows calling check() for plugin requirements -// without passing the IOrganizer. -class PluginRequirementProxy { public: - std::vector problems() const; - QString description(unsigned int id) const; + /** + * @return true if the plugin can be enabled (all requirements are met). + */ + bool canEnable() const; -private: + /** + * @return the proxy that created this plugin, if any. + */ + MOBase::IPluginProxy* proxy() const; - const MOBase::IPluginRequirement* m_Requirement; - OrganizerProxy* m_Proxy; + /** + * @return the list of problems to be resolved before enabling the plugin. + */ + std::vector problems() const; - PluginRequirementProxy(const MOBase::IPluginRequirement* requirement, OrganizerProxy* proxy); + /** + * @return the name of the games (gameName()) this plugin can be used with, or an empty + * list if this plugin does not require particular games. + */ + QStringList requiredGames() const; + + /** + * @return the list of plugins currently enabled that would have to be disabled + * if this plugin was disabled. + */ + std::vector requiredFor() const; + +private: + + // Accumulator version for requiredFor() to avoid infinite recursion. + void requiredFor(std::vector& required, std::set& visited) const; friend class PluginContainer; + PluginContainer* m_PluginContainer; + MOBase::IPlugin* m_Plugin; + MOBase::IPluginProxy* m_PluginProxy; + std::vector> m_Requirements; + MOBase::IOrganizer* m_Organizer; + std::vector m_RequiredFor; + + PluginRequirements( + PluginContainer* pluginContainer, MOBase::IPlugin* plugin, + MOBase::IOrganizer* proxy, MOBase::IPluginProxy* pluginProxy); + }; @@ -175,6 +228,11 @@ public: MOBase::IPlugin* plugin(MOBase::IPluginDiagnose* diagnose) const; MOBase::IPlugin* plugin(MOBase::IPluginFileMapper* mapper) const; + /** + * @return the IPlugin interface to the currently managed game. + */ + MOBase::IPlugin* managedGame() const; + /** * @brief Check if the given plugin is enabled. * @@ -182,13 +240,23 @@ public: * * @return true if the plugin is enabled, false otherwise. */ - bool isEnabled(MOBase::IPlugin *plugin) const; + bool isEnabled(MOBase::IPlugin* plugin) const; // These are friendly methods that called isEnabled(plugin(arg)). bool isEnabled(QString const& pluginName) const; bool isEnabled(MOBase::IPluginDiagnose* diagnose) const; bool isEnabled(MOBase::IPluginFileMapper* mapper) const; + /** + * @brief Enable or disable a plugin. + * + * @param plugin The plugin to enable or disable. + * @param enable true to enable, false to disable. + * @param dependencies If true and enable is false, dependencies will also + * be disabled (see PluginRequirements::requiredFor). + */ + void setEnabled(MOBase::IPlugin* plugin, bool enable, bool dependencies = true); + /** * @brief Retrieve the requirements for the given plugin. * @@ -196,7 +264,7 @@ public: * * @return the requirements (as proxy) for the given plugin. */ - std::vector requirements(MOBase::IPlugin* plugin) const; + const PluginRequirements& requirements(MOBase::IPlugin* plugin) const; /** * @brief Retrieved the (localized) names of interfaces implemented by the given @@ -244,6 +312,8 @@ signals: private: + friend class PluginRequirements; + /** * @brief Find the QObject* corresponding to the given plugin. * @@ -253,11 +323,19 @@ private: */ QObject* as_qobject(MOBase::IPlugin* plugin) const; + /** + * @brief Initialize a plugin. + * + * @param plugin The plugin to initialize. + * @param proxy The proxy that created this plugin (can be null). + * + * @return true if the plugin was initialized correctly, false otherwise. + */ + bool initPlugin(MOBase::IPlugin *plugin, MOBase::IPluginProxy* proxy); - bool initPlugin(MOBase::IPlugin *plugin); - bool initProxyPlugin(MOBase::IPlugin *plugin); void registerGame(MOBase::IPluginGame *game); - bool registerPlugin(QObject *pluginObj, const QString &fileName); + + bool registerPlugin(QObject *pluginObj, const QString &fileName, MOBase::IPluginProxy *proxy); OrganizerCore *m_Organizer; @@ -268,8 +346,7 @@ private: // This maps allow access to IPlugin* from name or diagnose/mapper object. AccessPluginMap m_AccessPlugins; - std::map m_Proxies; - std::map>> m_Requirements; + std::map m_Requirements; std::map m_SupportedGames; std::vector m_DiagnosisConnections; diff --git a/src/settings.cpp b/src/settings.cpp index 0f661bfb..a76d5e76 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1288,6 +1288,11 @@ void PluginSettings::registerPlugin(IPlugin *plugin) temp.toString(), setting.key, plugin->name()); temp = setting.defaultValue; + + // If there was no previous "enabled" value, skip it: + if (setting.key == "enabled") { + continue; + } } m_PluginSettings[plugin->name()][setting.key] = temp; @@ -1297,9 +1302,15 @@ void PluginSettings::registerPlugin(IPlugin *plugin) .arg(setting.defaultValue.toString()); } - if (!m_PluginSettings.contains("enabled")) { - m_PluginSettings[plugin->name()]["enabled"] = true; - m_PluginDescriptions[plugin->name()]["enabled"] = QString(); + // Handle previous "enabled" settings: + if (m_PluginSettings[plugin->name()].contains("enabled")) { + setPersistent(plugin->name(), "enabled", m_PluginSettings[plugin->name()]["enabled"].toBool(), true); + m_PluginSettings[plugin->name()].remove("enabled"); + m_PluginDescriptions[plugin->name()].remove("enabled"); + + // We need to drop it manually in Settings since it is not possible to remove plugin + // settings: + remove(m_Settings, "Plugins", plugin->name() + "/enabled"); } } diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index 85c5a4e4..4fd34b21 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -1127,6 +1127,9 @@ + + 6 + @@ -1172,6 +1175,13 @@ + + + + Enabled + + + diff --git a/src/settingsdialogplugins.cpp b/src/settingsdialogplugins.cpp index 5faa0dc9..8a70475c 100644 --- a/src/settingsdialogplugins.cpp +++ b/src/settingsdialogplugins.cpp @@ -3,9 +3,10 @@ #include "noeditdelegate.h" #include +#include "organizercore.h" #include "plugincontainer.h" -using MOBase::IPlugin; +using namespace MOBase; PluginsSettingsTab::PluginsSettingsTab(Settings& s, PluginContainer* pluginContainer, SettingsDialog& d) : SettingsTab(s, d), m_pluginContainer(pluginContainer) @@ -66,15 +67,36 @@ PluginsSettingsTab::PluginsSettingsTab(Settings& s, PluginContainer* pluginConta QObject::connect( ui->pluginsList, &QTreeWidget::currentItemChanged, [&](auto* current, auto* previous) { on_pluginsList_currentItemChanged(current, previous); }); + QObject::connect( + ui->enabledCheckbox, &QCheckBox::clicked, + [&](bool checked) { on_checkboxEnabled_clicked(checked); }); QShortcut *delShortcut = new QShortcut( QKeySequence(Qt::Key_Delete), ui->pluginBlacklist); QObject::connect(delShortcut, &QShortcut::activated, &dialog(), [&] { deleteBlacklistItem(); }); - QObject::connect(&m_filter, &MOBase::FilterWidget::changed, [&] { filterPluginList(); }); + QObject::connect(&m_filter, &FilterWidget::changed, [&] { filterPluginList(); }); + updateListItems(); filterPluginList(); } +void PluginsSettingsTab::updateListItems() +{ + for (auto i = 0; i < ui->pluginsList->topLevelItemCount(); ++i) { + auto* topLevelItem = ui->pluginsList->topLevelItem(i); + for (auto j = 0; j < topLevelItem->childCount(); ++j) { + auto* item = topLevelItem->child(j); + auto* plugin = this->plugin(item); + + if (!m_pluginContainer->implementInterface(plugin) + && !m_pluginContainer->isEnabled(plugin)) { + item->setBackgroundColor(0, Qt::gray); + } + } + } + +} + void PluginsSettingsTab::filterPluginList() { QTreeWidgetItem* firstNotHidden = nullptr; @@ -109,7 +131,7 @@ void PluginsSettingsTab::filterPluginList() auto selectedItems = ui->pluginsList->selectedItems(); if (!selectedItems.isEmpty() && selectedItems[0]->isHidden()) { selectedItems[0]->setSelected(false); - + if (firstNotHidden) { firstNotHidden->setSelected(true); } @@ -150,6 +172,71 @@ void PluginsSettingsTab::closing() storeSettings(ui->pluginsList->currentItem()); } +void PluginsSettingsTab::on_checkboxEnabled_clicked(bool checked) +{ + // Retrieve the plugin: + auto *item = ui->pluginsList->currentItem(); + if (!item || !item->data(0, ROLE_PLUGIN).isValid()) { + return; + } + IPlugin* plugin = this->plugin(item); + const auto& requirements = m_pluginContainer->requirements(plugin); + + // User wants to enable: + if (checked) { + auto problems = requirements.problems(); + if (!problems.empty()) { + QStringList descriptions; + for (auto& problem : problems) { + descriptions.append(problem.description()); + } + QMessageBox::warning( + parentWidget(), QObject::tr("Cannot enable plugin"), + QObject::tr("

This plugin cannot be enabled:

    %1
") + .arg("
  • " + descriptions.join("
  • ") + "
  • "), QMessageBox::Ok); + ui->enabledCheckbox->setChecked(false); + return; + } + + m_pluginContainer->setEnabled(plugin, false, true); + } + else { + // Custom check for proxy + current game: + if (m_pluginContainer->implementInterface(plugin)) { + auto* game = m_pluginContainer->managedGame(); + if (m_pluginContainer->requirements(game).proxy() == plugin) { + QMessageBox::warning( + parentWidget(), QObject::tr("Cannot disable plugin"), + QObject::tr("This plugin is used by the current game plugin and cannot disabled."), QMessageBox::Ok); + ui->enabledCheckbox->setChecked(true); + return; + } + } + + // Check if the plugins is required for other plugins: + auto requiredFor = requirements.requiredFor(); + if (!requiredFor.empty()) { + QStringList pluginNames; + for (auto& p : requiredFor) { + pluginNames.append(p->localizedName()); + } + pluginNames.sort(); + QString message = QObject::tr( + "

    Disabling this plugin will also disable the following plugins:

      %1

    Do you want to continue?

    ") + .arg("
  • " + pluginNames.join("
  • ") + "
  • "); + if (QMessageBox::warning( + parentWidget(), QObject::tr("Really disable plugin?"), message, + QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) { + ui->enabledCheckbox->setChecked(true); + return; + } + } + m_pluginContainer->setEnabled(plugin, false, true); + } + + updateListItems(); +} + void PluginsSettingsTab::on_pluginsList_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous) { storeSettings(previous); @@ -164,6 +251,10 @@ void PluginsSettingsTab::on_pluginsList_currentItemChanged(QTreeWidgetItem *curr ui->versionLabel->setText(plugin->version().canonicalString()); ui->descriptionLabel->setText(plugin->description()); + ui->enabledCheckbox->setVisible( + !m_pluginContainer->implementInterface(plugin)); + ui->enabledCheckbox->setChecked(m_pluginContainer->isEnabled(plugin)); + QVariantMap settings = current->data(0, ROLE_SETTINGS).toMap(); QVariantMap descriptions = current->data(0, ROLE_DESCRIPTIONS).toMap(); ui->pluginSettingsList->setEnabled(settings.count() != 0); diff --git a/src/settingsdialogplugins.h b/src/settingsdialogplugins.h index add8fede..3de0d7dc 100644 --- a/src/settingsdialogplugins.h +++ b/src/settingsdialogplugins.h @@ -16,10 +16,17 @@ public: private: void on_pluginsList_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous); + void on_checkboxEnabled_clicked(bool checked); void deleteBlacklistItem(); void storeSettings(QTreeWidgetItem *pluginItem); private slots: + + /** + * @brief Update the list item to display inactive plugins. + */ + void updateListItems(); + /** * @brief Filter the plugin list according to the filter widget. * -- cgit v1.3.1 From 0dddc5eb7b60efd4f124485fd6e3e982c04f8a28 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Wed, 11 Nov 2020 14:08:23 +0100 Subject: Fix handling of previous 'enabled' settings. --- src/settings.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'src/settings.cpp') diff --git a/src/settings.cpp b/src/settings.cpp index a76d5e76..db48cfd2 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1280,19 +1280,22 @@ void PluginSettings::registerPlugin(IPlugin *plugin) const QString settingName = plugin->name() + "/" + setting.key; QVariant temp = get( - m_Settings, "Plugins", settingName, setting.defaultValue); + m_Settings, "Plugins", settingName, QVariant()); - if (!temp.convert(setting.defaultValue.type())) { + // No previous enabled? Skip. + if (setting.key == "enabled" && (!temp.isValid() || !temp.canConvert())) { + continue; + } + + if (!temp.isValid()) { + temp = setting.defaultValue; + } + else if (!temp.convert(setting.defaultValue.type())) { log::warn( "failed to interpret \"{}\" as correct type for \"{}\" in plugin \"{}\", using default", temp.toString(), setting.key, plugin->name()); temp = setting.defaultValue; - - // If there was no previous "enabled" value, skip it: - if (setting.key == "enabled") { - continue; - } } m_PluginSettings[plugin->name()][setting.key] = temp; -- cgit v1.3.1