summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMikaƫl Capelle <capelle.mikael@gmail.com>2020-10-01 18:52:35 +0200
committerGitHub <noreply@github.com>2020-10-01 18:52:35 +0200
commit4167e6768e3d82f831982588347a5a8606fe82f6 (patch)
treeb31dc6b9711ed0681d28beb5a1314f10474950ce /src
parentcd3f496a5b9f6cc090c66a226d4f7f7557c9a8e1 (diff)
parent475fc0b813497d81aed92b0659cb2213dd9ce14f (diff)
Merge pull request #1248 from Holt59/iplugin-interface-improvements
Better display of MO2 plugins
Diffstat (limited to 'src')
-rw-r--r--src/plugincontainer.cpp100
-rw-r--r--src/plugincontainer.h86
-rw-r--r--src/settingsdialog.cpp2
-rw-r--r--src/settingsdialog.ui263
-rw-r--r--src/settingsdialogplugins.cpp138
-rw-r--r--src/settingsdialogplugins.h31
6 files changed, 487 insertions, 133 deletions
diff --git a/src/plugincontainer.cpp b/src/plugincontainer.cpp
index d989fac9..60acc63c 100644
--- a/src/plugincontainer.cpp
+++ b/src/plugincontainer.cpp
@@ -21,6 +21,35 @@ using namespace MOShared;
namespace bf = boost::fusion;
+template <class T>
+struct PluginTypeName;
+
+template <> struct PluginTypeName<MOBase::IPlugin> { static QString value() { return QT_TR_NOOP("Plugin"); } };
+template <> struct PluginTypeName<MOBase::IPluginDiagnose> { static QString value() { return QT_TR_NOOP("Diagnose"); } };
+template <> struct PluginTypeName<MOBase::IPluginGame> { static QString value() { return QT_TR_NOOP("Game"); } };
+template <> struct PluginTypeName<MOBase::IPluginInstaller> { static QString value() { return QT_TR_NOOP("Installer"); } };
+template <> struct PluginTypeName<MOBase::IPluginModPage> { static QString value() { return QT_TR_NOOP("Mod Page"); } };
+template <> struct PluginTypeName<MOBase::IPluginPreview> { static QString value() { return QT_TR_NOOP("Preview"); } };
+template <> struct PluginTypeName<MOBase::IPluginTool> { static QString value() { return QT_TR_NOOP("Tool"); } };
+template <> struct PluginTypeName<MOBase::IPluginProxy> { static QString value() { return QT_TR_NOOP("Proxy"); } };
+template <> struct PluginTypeName<MOBase::IPluginFileMapper> { static QString value() { return QT_TR_NOOP("File Mapper"); } };
+
+
+QStringList PluginContainer::pluginInterfaces()
+{
+ // Find all the names:
+ QStringList names;
+ boost::mp11::mp_for_each<PluginTypeOrder>([&names](const auto* p) {
+ using plugin_type = std::decay_t<decltype(*p)>;
+ auto name = PluginTypeName<plugin_type>::value();
+ if (!name.isEmpty()) {
+ names.append(name);
+ }
+ });
+
+ return names;
+}
+
PluginContainer::PluginContainer(OrganizerCore *organizer)
: m_Organizer(organizer)
@@ -33,6 +62,7 @@ PluginContainer::~PluginContainer() {
unloadPlugins();
}
+
void PluginContainer::setUserInterface(IUserInterface *userInterface, QWidget *widget)
{
for (IPluginProxy *proxy : bf::at_key<IPluginProxy>(m_Plugins)) {
@@ -53,6 +83,61 @@ void PluginContainer::setUserInterface(IUserInterface *userInterface, QWidget *w
}
+QStringList PluginContainer::implementedInterfaces(IPlugin* plugin) const
+{
+ // We need a QObject to be able to qobject_cast<> to the plugin types:
+ QObject* oPlugin = as_qobject(plugin);
+
+ if (!oPlugin) {
+ return {};
+ }
+
+ // Find all the names:
+ QStringList names;
+ boost::mp11::mp_for_each<PluginTypeOrder>([oPlugin, &names](const auto* p) {
+ using plugin_type = std::decay_t<decltype(*p)>;
+ if (qobject_cast<plugin_type*>(oPlugin)) {
+ auto name = PluginTypeName<plugin_type>::value();
+ if (!name.isEmpty()) {
+ names.append(name);
+ }
+ }
+ });
+
+ // If the plugin implements at least one interface other than IPlugin, remove IPlugin:
+ if (names.size() > 1) {
+ names.removeAll(PluginTypeName<IPlugin>::value());
+ }
+
+ return names;
+}
+
+
+QString PluginContainer::topImplementedInterface(IPlugin* plugin) const
+{
+ // We need a QObject to be able to qobject_cast<> to the plugin types:
+ QObject* oPlugin = as_qobject(plugin);
+
+ if (!oPlugin) {
+ return {};
+ }
+
+ // Find all the names:
+ QString name;
+ boost::mp11::mp_for_each<PluginTypeOrder>([oPlugin, &name](auto* p) {
+ using plugin_type = std::decay_t<decltype(*p)>;
+ if (name.isEmpty() && qobject_cast<plugin_type*>(oPlugin)) {
+ auto tname = PluginTypeName<plugin_type>::value();
+ if (!tname.isEmpty()) {
+ name = tname;
+ }
+ }
+ });
+
+ return name;
+}
+
+
QStringList PluginContainer::pluginFileNames() const
{
QStringList result;
@@ -69,6 +154,21 @@ QStringList PluginContainer::pluginFileNames() const
}
+QObject* PluginContainer::as_qobject(MOBase::IPlugin* plugin) const
+{
+ // Find the correspond QObject - Can this be done safely with a cast?
+ auto& objects = bf::at_key<QObject>(m_Plugins);
+ auto it = std::find_if(std::begin(objects), std::end(objects), [plugin](QObject* obj) {
+ return qobject_cast<IPlugin*>(obj) == plugin;
+ });
+
+ if (it == std::end(objects)) {
+ return nullptr;
+ }
+
+ return *it;
+}
+
bool PluginContainer::verifyPlugin(IPlugin *plugin)
{
if (plugin == nullptr) {
diff --git a/src/plugincontainer.h b/src/plugincontainer.h
index d405198a..07363ee7 100644
--- a/src/plugincontainer.h
+++ b/src/plugincontainer.h
@@ -19,6 +19,7 @@ class IUserInterface;
#ifndef Q_MOC_RUN
#include <boost/fusion/container.hpp>
#include <boost/fusion/include/at_key.hpp>
+#include <boost/mp11.hpp>
#endif // Q_MOC_RUN
#include <vector>
@@ -46,6 +47,37 @@ private:
static const unsigned int PROBLEM_PLUGINSNOTLOADED = 1;
+ /**
+ * This typedefs defines the order of plugin interface. This is increasing order of
+ * importance".
+ *
+ * @note IPlugin is the less important interface, followed by IPluginDiagnose and
+ * IPluginFileMapper as those are usually implemented together with another interface.
+ * Other interfaces are in a alphabetical order since it is unlikely a plugin will
+ * implement multiple ones.
+ */
+ using PluginTypeOrder =
+ boost::mp11::mp_transform<
+ std::add_pointer_t,
+ boost::mp11::mp_list<
+ MOBase::IPluginGame, MOBase::IPluginInstaller, MOBase::IPluginModPage, MOBase::IPluginPreview,
+ MOBase::IPluginProxy, MOBase::IPluginTool, MOBase::IPluginDiagnose, MOBase::IPluginFileMapper,
+ MOBase::IPlugin
+ >
+ >;
+
+ static_assert(
+ boost::mp11::mp_size<PluginTypeOrder>::value == boost::mp11::mp_size<PluginContainer::PluginMap>::value - 1);
+
+public:
+
+ /**
+ * @brief Retrieved the (localized) names of the various plugin interfaces.
+ *
+ * @return the (localized) names of the various plugin interfaces.
+ */
+ static QStringList pluginInterfaces();
+
public:
PluginContainer(OrganizerCore *organizer);
@@ -56,16 +88,60 @@ public:
void loadPlugins();
void unloadPlugins();
+ /**
+ * @brief Find the game plugin corresponding to the given name.
+ *
+ * @param name The name of the game to find a plugin for (as returned by
+ * IPluginGame::gameName()).
+ *
+ * @return the game plugin for the given name, or a null pointer if no
+ * plugin exists for this game.
+ */
MOBase::IPluginGame *managedGame(const QString &name) const;
+ /**
+ * @brief Retrieve the list of plugins of the given type.
+ *
+ * @return the list of plugins of the specified type.
+ *
+ * @tparam T The type of plugin to retrieve.
+ */
template <typename T>
const std::vector<T*> &plugins() const {
typename boost::fusion::result_of::at_key<const PluginMap, T>::type temp = boost::fusion::at_key<T>(m_Plugins);
return temp;
}
+ /**
+ * @brief Retrieved the (localized) names of interfaces implemented by the given
+ * plugin.
+ *
+ * @param plugin The plugin to retrieve interface for.
+ *
+ * @return the (localized) names of interfaces implemented by this plugin.
+ */
+ QStringList implementedInterfaces(MOBase::IPlugin* plugin) const;
+
+ /**
+ * @brief Return the (localized) name of the most important interface implemented by
+ * the given plugin.
+ *
+ * The order of interfaces is defined in X.
+ *
+ * @param plugin The plugin to retrieve the interface for.
+ *
+ * @return the (localized) name of the most important interface implemented by this plugin.
+ */
+ QString topImplementedInterface(MOBase::IPlugin* plugin) const;
+
+ /**
+ * @return the preview generator.
+ */
const PreviewGenerator &previewGenerator() const;
+ /**
+ * @return the list of plugin file names, including proxied plugins.
+ */
QStringList pluginFileNames() const;
public: // IPluginDiagnose interface
@@ -82,6 +158,16 @@ signals:
private:
+ /**
+ * @brief Find the QObject* corresponding to the given plugin.
+ *
+ * @param plugin The plugin to find the QObject* for.
+ *
+ * @return a QObject* for the given plugin.
+ */
+ QObject* as_qobject(MOBase::IPlugin* plugin) const;
+
+
bool verifyPlugin(MOBase::IPlugin *plugin);
void registerGame(MOBase::IPluginGame *game);
bool registerPlugin(QObject *pluginObj, const QString &fileName);
diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp
index daccfba9..87c7201d 100644
--- a/src/settingsdialog.cpp
+++ b/src/settingsdialog.cpp
@@ -43,7 +43,7 @@ SettingsDialog::SettingsDialog(PluginContainer *pluginContainer, Settings& setti
m_tabs.push_back(std::unique_ptr<SettingsTab>(new DiagnosticsSettingsTab(settings, *this)));
m_tabs.push_back(std::unique_ptr<SettingsTab>(new NexusSettingsTab(settings, *this)));
m_tabs.push_back(std::unique_ptr<SettingsTab>(new SteamSettingsTab(settings, *this)));
- m_tabs.push_back(std::unique_ptr<SettingsTab>(new PluginsSettingsTab(settings, *this)));
+ m_tabs.push_back(std::unique_ptr<SettingsTab>(new PluginsSettingsTab(settings, m_pluginContainer, *this)));
m_tabs.push_back(std::unique_ptr<SettingsTab>(new WorkaroundsSettingsTab(settings, *this)));
}
diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui
index 2ceb91db..33c1c2ee 100644
--- a/src/settingsdialog.ui
+++ b/src/settingsdialog.ui
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>586</width>
- <height>491</height>
+ <width>820</width>
+ <height>652</height>
</rect>
</property>
<property name="windowTitle">
@@ -1038,119 +1038,172 @@
<attribute name="title">
<string>Plugins</string>
</attribute>
- <layout class="QVBoxLayout" name="verticalLayout_9" stretch="0,0,0">
+ <layout class="QVBoxLayout" name="verticalLayout_9">
<item>
- <layout class="QHBoxLayout" name="horizontalLayout_9">
- <item>
- <widget class="QListWidget" name="pluginsList">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Expanding">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="sortingEnabled">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
- <layout class="QVBoxLayout" name="verticalLayout_7" stretch="0,1">
- <item>
- <layout class="QFormLayout" name="formLayout_2">
- <item row="0" column="0">
- <widget class="QLabel" name="label_13">
- <property name="text">
- <string>Author:</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QLabel" name="authorLabel">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="label_15">
- <property name="text">
- <string>Version:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QLabel" name="versionLabel">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="label_14">
- <property name="text">
- <string>Description:</string>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="QLabel" name="descriptionLabel">
- <property name="text">
- <string/>
- </property>
- <property name="wordWrap">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- </layout>
- </item>
+ <widget class="QSplitter" name="splitter">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="handleWidth">
+ <number>2</number>
+ </property>
+ <widget class="QWidget" name="widget" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>4</verstretch>
+ </sizepolicy>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
- <widget class="QTreeWidget" name="pluginSettingsList">
- <property name="indentation">
- <number>0</number>
+ <widget class="QSplitter" name="splitter_2">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
</property>
- <property name="rootIsDecorated">
- <bool>false</bool>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
</property>
- <property name="itemsExpandable">
- <bool>false</bool>
+ <property name="handleWidth">
+ <number>2</number>
</property>
- <property name="expandsOnDoubleClick">
- <bool>false</bool>
+ <widget class="QWidget" name="widget" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_15">
+ <item>
+ <widget class="QTreeWidget" name="pluginsList">
+ <column>
+ <property name="text">
+ <string notr="true">1</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <item>
+ <widget class="QLineEdit" name="pluginFilterEdit">
+ <property name="placeholderText">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="widget" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_7" stretch="0,1">
+ <item>
+ <layout class="QFormLayout" name="formLayout_2">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_13">
+ <property name="text">
+ <string>Author:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="authorLabel">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_15">
+ <property name="text">
+ <string>Version:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="versionLabel">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="descriptionLabel">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_14">
+ <property name="text">
+ <string>Description:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QTreeWidget" name="pluginSettingsList">
+ <property name="indentation">
+ <number>0</number>
+ </property>
+ <property name="rootIsDecorated">
+ <bool>false</bool>
+ </property>
+ <property name="itemsExpandable">
+ <bool>false</bool>
+ </property>
+ <property name="expandsOnDoubleClick">
+ <bool>false</bool>
+ </property>
+ <attribute name="headerVisible">
+ <bool>false</bool>
+ </attribute>
+ <attribute name="headerDefaultSectionSize">
+ <number>170</number>
+ </attribute>
+ <column>
+ <property name="text">
+ <string>Key</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Value</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="verticalWidget" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_16">
+ <item>
+ <widget class="QLabel" name="label_18">
+ <property name="text">
+ <string>Blacklisted Plugins (use &lt;del&gt; to remove):</string>
</property>
- <attribute name="headerVisible">
- <bool>false</bool>
- </attribute>
- <attribute name="headerDefaultSectionSize">
- <number>170</number>
- </attribute>
- <column>
- <property name="text">
- <string>Key</string>
- </property>
- </column>
- <column>
- <property name="text">
- <string>Value</string>
- </property>
- </column>
</widget>
</item>
+ <item>
+ <widget class="QListWidget" name="pluginBlacklist"/>
+ </item>
</layout>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QLabel" name="label_18">
- <property name="text">
- <string>Blacklisted Plugins (use &lt;del&gt; to remove):</string>
- </property>
+ </widget>
</widget>
</item>
- <item>
- <widget class="QListWidget" name="pluginBlacklist"/>
- </item>
</layout>
</widget>
<widget class="QWidget" name="workaroundTab">
@@ -1613,9 +1666,7 @@ programs you are intentionally running.</string>
<tabstop>preferredServersList</tabstop>
<tabstop>steamUserEdit</tabstop>
<tabstop>steamPassEdit</tabstop>
- <tabstop>pluginsList</tabstop>
<tabstop>pluginSettingsList</tabstop>
- <tabstop>pluginBlacklist</tabstop>
<tabstop>appIDEdit</tabstop>
<tabstop>mechanismBox</tabstop>
<tabstop>hideUncheckedBox</tabstop>
diff --git a/src/settingsdialogplugins.cpp b/src/settingsdialogplugins.cpp
index c84d0556..5faa0dc9 100644
--- a/src/settingsdialogplugins.cpp
+++ b/src/settingsdialogplugins.cpp
@@ -3,47 +3,135 @@
#include "noeditdelegate.h"
#include <iplugin.h>
+#include "plugincontainer.h"
+
using MOBase::IPlugin;
-PluginsSettingsTab::PluginsSettingsTab(Settings& s, SettingsDialog& d)
- : SettingsTab(s, d)
+PluginsSettingsTab::PluginsSettingsTab(Settings& s, PluginContainer* pluginContainer, SettingsDialog& d)
+ : SettingsTab(s, d), m_pluginContainer(pluginContainer)
{
ui->pluginSettingsList->setStyleSheet("QTreeWidget::item {padding-right: 10px;}");
+ // Create top-level tree widget:
+ QStringList pluginInterfaces = m_pluginContainer->pluginInterfaces();
+ pluginInterfaces.sort(Qt::CaseInsensitive);
+ std::map<QString, QTreeWidgetItem*> topItems;
+ for (QString interfaceName : pluginInterfaces) {
+ auto* item = new QTreeWidgetItem(ui->pluginsList, { interfaceName });
+ item->setFlags(item->flags() & ~Qt::ItemIsSelectable);
+ auto font = item->font(0);
+ font.setBold(true);
+ item->setFont(0, font);
+ topItems[interfaceName] = item;
+ item->setExpanded(true);
+ }
+ ui->pluginsList->setHeaderHidden(true);
+
// display plugin settings
QSet<QString> handledNames;
- for (IPlugin *plugin : settings().plugins().plugins()) {
- if (handledNames.contains(plugin->name()))
+ for (IPlugin* plugin : settings().plugins().plugins()) {
+ if (handledNames.contains(plugin->name())) {
+ continue;
+ }
+ if (!m_filter.matches([plugin](const QRegularExpression& regex) {
+ return regex.match(plugin->localizedName()).hasMatch();
+ })) {
continue;
- QListWidgetItem *listItem = new QListWidgetItem(plugin->name(), ui->pluginsList);
- listItem->setData(Qt::UserRole, QVariant::fromValue((void*)plugin));
- listItem->setData(Qt::UserRole + 1, settings().plugins().settings(plugin->name()));
- listItem->setData(Qt::UserRole + 2, settings().plugins().descriptions(plugin->name()));
- ui->pluginsList->addItem(listItem);
+ }
+ QTreeWidgetItem* listItem = new QTreeWidgetItem(
+ topItems.at(m_pluginContainer->topImplementedInterface(plugin)));
+ listItem->setData(0, Qt::DisplayRole, plugin->localizedName());
+ listItem->setData(0, ROLE_PLUGIN, QVariant::fromValue((void*)plugin));
+ listItem->setData(0, ROLE_SETTINGS, settings().plugins().settings(plugin->name()));
+ listItem->setData(0, ROLE_DESCRIPTIONS, settings().plugins().descriptions(plugin->name()));
+
handledNames.insert(plugin->name());
}
+ for (auto& [k, item] : topItems) {
+ if (item->childCount() == 0) {
+ item->setHidden(true);
+ }
+ }
+
+ ui->pluginsList->sortByColumn(0, Qt::AscendingOrder);
+
// display plugin blacklist
for (const QString &pluginName : settings().plugins().blacklist()) {
ui->pluginBlacklist->addItem(pluginName);
}
+ m_filter.setEdit(ui->pluginFilterEdit);
+
QObject::connect(
- ui->pluginsList, &QListWidget::currentItemChanged,
+ ui->pluginsList, &QTreeWidget::currentItemChanged,
[&](auto* current, auto* previous) { on_pluginsList_currentItemChanged(current, previous); });
QShortcut *delShortcut = new QShortcut(
QKeySequence(Qt::Key_Delete), ui->pluginBlacklist);
- QObject::connect(delShortcut, &QShortcut::activated, &dialog(), [&]{ deleteBlacklistItem(); });
+ QObject::connect(delShortcut, &QShortcut::activated, &dialog(), [&] { deleteBlacklistItem(); });
+ QObject::connect(&m_filter, &MOBase::FilterWidget::changed, [&] { filterPluginList(); });
+
+ filterPluginList();
+}
+
+void PluginsSettingsTab::filterPluginList()
+{
+ QTreeWidgetItem* firstNotHidden = nullptr;
+
+ for (auto i = 0; i < ui->pluginsList->topLevelItemCount(); ++i) {
+ auto* topLevelItem = ui->pluginsList->topLevelItem(i);
+
+ bool found = false;
+ for (auto j = 0; j < topLevelItem->childCount(); ++j) {
+ auto* item = topLevelItem->child(j);
+ auto* plugin = this->plugin(item);
+
+ if (m_filter.matches([plugin](const QRegularExpression& regex) {
+ return regex.match(plugin->localizedName()).hasMatch();
+ })) {
+ found = true;
+ item->setHidden(false);
+
+ if (firstNotHidden == nullptr) {
+ firstNotHidden = item;
+ }
+ }
+ else {
+ item->setHidden(true);
+ }
+ }
+
+ topLevelItem->setHidden(!found);
+ }
+
+ // Unselect item if hidden:
+ auto selectedItems = ui->pluginsList->selectedItems();
+ if (!selectedItems.isEmpty() && selectedItems[0]->isHidden()) {
+ selectedItems[0]->setSelected(false);
+
+ if (firstNotHidden) {
+ firstNotHidden->setSelected(true);
+ }
+ }
+
+}
+
+IPlugin* PluginsSettingsTab::plugin(QTreeWidgetItem* pluginItem) const
+{
+ return static_cast<IPlugin*>(qvariant_cast<void*>(pluginItem->data(0, ROLE_PLUGIN)));
}
void PluginsSettingsTab::update()
{
// transfer plugin settings to in-memory structure
- for (int i = 0; i < ui->pluginsList->count(); ++i) {
- QListWidgetItem *item = ui->pluginsList->item(i);
- settings().plugins().setSettings(
- item->text(), item->data(Qt::UserRole + 1).toMap());
+ for (int i = 0; i < ui->pluginsList->topLevelItemCount(); ++i) {
+ auto *topLevelItem = ui->pluginsList->topLevelItem(i);
+ for (int j = 0; j < topLevelItem->childCount(); ++j) {
+ auto* item = topLevelItem->child(j);
+ settings().plugins().setSettings(
+ plugin(item)->name(), item->data(0, ROLE_SETTINGS).toMap());
+ }
}
// set plugin blacklist
@@ -62,18 +150,22 @@ void PluginsSettingsTab::closing()
storeSettings(ui->pluginsList->currentItem());
}
-void PluginsSettingsTab::on_pluginsList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)
+void PluginsSettingsTab::on_pluginsList_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
{
storeSettings(previous);
+ if (!current->data(0, ROLE_PLUGIN).isValid()) {
+ return;
+ }
+
ui->pluginSettingsList->clear();
- IPlugin *plugin = static_cast<IPlugin*>(current->data(Qt::UserRole).value<void*>());
+ IPlugin* plugin = this->plugin(current);
ui->authorLabel->setText(plugin->author());
ui->versionLabel->setText(plugin->version().canonicalString());
ui->descriptionLabel->setText(plugin->description());
- QVariantMap settings = current->data(Qt::UserRole + 1).toMap();
- QVariantMap descriptions = current->data(Qt::UserRole + 2).toMap();
+ QVariantMap settings = current->data(0, ROLE_SETTINGS).toMap();
+ QVariantMap descriptions = current->data(0, ROLE_DESCRIPTIONS).toMap();
ui->pluginSettingsList->setEnabled(settings.count() != 0);
for (auto iter = settings.begin(); iter != settings.end(); ++iter) {
QTreeWidgetItem *newItem = new QTreeWidgetItem(QStringList(iter.key()));
@@ -104,16 +196,16 @@ void PluginsSettingsTab::deleteBlacklistItem()
ui->pluginBlacklist->takeItem(ui->pluginBlacklist->currentIndex().row());
}
-void PluginsSettingsTab::storeSettings(QListWidgetItem *pluginItem)
+void PluginsSettingsTab::storeSettings(QTreeWidgetItem *pluginItem)
{
- if (pluginItem != nullptr) {
- QVariantMap settings = pluginItem->data(Qt::UserRole + 1).toMap();
+ if (pluginItem != nullptr && pluginItem->data(0, ROLE_PLUGIN).isValid()) {
+ QVariantMap settings = pluginItem->data(0, ROLE_SETTINGS).toMap();
for (int i = 0; i < ui->pluginSettingsList->topLevelItemCount(); ++i) {
const QTreeWidgetItem *item = ui->pluginSettingsList->topLevelItem(i);
settings[item->text(0)] = item->data(1, Qt::DisplayRole);
}
- pluginItem->setData(Qt::UserRole + 1, settings);
+ pluginItem->setData(0, ROLE_SETTINGS, settings);
}
}
diff --git a/src/settingsdialogplugins.h b/src/settingsdialogplugins.h
index 8e2dae2a..add8fede 100644
--- a/src/settingsdialogplugins.h
+++ b/src/settingsdialogplugins.h
@@ -1,21 +1,46 @@
#ifndef SETTINGSDIALOGPLUGINS_H
#define SETTINGSDIALOGPLUGINS_H
+#include "filterwidget.h"
+
#include "settings.h"
#include "settingsdialog.h"
class PluginsSettingsTab : public SettingsTab
{
public:
- PluginsSettingsTab(Settings& settings, SettingsDialog& dialog);
+ PluginsSettingsTab(Settings& settings, PluginContainer* pluginContainer, SettingsDialog& dialog);
void update();
void closing() override;
private:
- void on_pluginsList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous);
+ void on_pluginsList_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous);
void deleteBlacklistItem();
- void storeSettings(QListWidgetItem *pluginItem);
+ void storeSettings(QTreeWidgetItem *pluginItem);
+
+private slots:
+ /**
+ * @brief Filter the plugin list according to the filter widget.
+ *
+ */
+ void filterPluginList();
+
+ /**
+ * @brief Retrieve the plugin associated to the given item in the list.
+ *
+ */
+ MOBase::IPlugin* plugin(QTreeWidgetItem *pluginItem) const;
+
+ constexpr static int ROLE_PLUGIN = Qt::UserRole;
+ constexpr static int ROLE_SETTINGS = Qt::UserRole + 1;
+ constexpr static int ROLE_DESCRIPTIONS = Qt::UserRole + 2;
+
+private:
+
+ PluginContainer* m_pluginContainer;
+
+ MOBase::FilterWidget m_filter;
};
#endif // SETTINGSDIALOGPLUGINS_H