Start updating the settings tab for extension.
Some checks failed
Lint ModOrganizer 2 / lint (push) Has been cancelled

This commit is contained in:
Mikaël Capelle 2024-08-12 10:01:43 +02:00
parent 890bee5444
commit 8006988b20
20 changed files with 361 additions and 108 deletions

View File

@ -29,7 +29,7 @@
"value": "x64"
},
"cacheVariables": {
"CMAKE_CXX_FLAGS": "/EHsc /MP /W4",
"CMAKE_CXX_FLAGS": "/EHsc /MP /W3",
"VCPKG_TARGET_TRIPLET": {
"type": "STRING",
"value": "x64-windows-static-md"

View File

@ -25,7 +25,7 @@ set_target_properties(organizer PROPERTIES
# disable translations because we want to be able to install somewhere else if
# required
mo2_configure_target(organizer WARNINGS 4 TRANSLATIONS OFF)
mo2_configure_target(organizer WARNINGS 3 TRANSLATIONS OFF)
# we add translations "manually" to handle MO2_INSTALL_IS_BIN
mo2_add_translations(organizer

View File

@ -1,10 +1,14 @@
#include "extensionmanager.h"
#include <log.h>
#include <uibase/log.h>
#include "organizercore.h"
using namespace MOBase;
namespace fs = std::filesystem;
ExtensionManager::ExtensionManager(OrganizerCore* core) : m_core{core} {}
void ExtensionManager::loadExtensions(fs::path const& directory)
{
for (const auto& entry : fs::directory_iterator{directory}) {
@ -60,8 +64,18 @@ const IExtension* ExtensionManager::extension(QString const& identifier) const
bool ExtensionManager::isEnabled(MOBase::IExtension const& extension) const
{
// TODO
return true;
if (!m_core) {
return true;
}
for (auto& requirement : extension.metadata().requirements()) {
// TODO: needs an organizerproxy...
// if (!requirement.check(m_core)) {
// return false;
//}
}
return m_core->settings().extensions().isEnabled(extension, true);
}
bool ExtensionManager::isEnabled(QString const& identifier) const

View File

@ -10,10 +10,15 @@
#include <uibase/extensions/extension.h>
#include "extensionwatcher.h"
#include "organizerproxy.h"
class OrganizerCore;
class ExtensionManager
{
public:
ExtensionManager(OrganizerCore* core);
// retrieve the list of currently loaded extensions
//
const auto& extensions() const { return m_extensions; }
@ -58,6 +63,8 @@ private:
void triggerWatchers(const MOBase::IExtension& extension) const;
private:
OrganizerCore* m_core;
std::unique_ptr<OrganizerProxy> m_proxy;
std::vector<std::unique_ptr<const MOBase::IExtension>> m_extensions;
using WatcherMap = boost::fusion::map<

View File

@ -4,9 +4,55 @@
using namespace MOBase;
static const QString EXTENSIONS_GROUP = "Extensions";
static const QString EXTENSIONS_ENABLED_GROUP = "ExtensionsEnabled";
static const QString PLUGINS_GROUP = "Plugins";
static const QString PLUGINS_PERSISTENT_GROUP = "PluginPersistance";
ExtensionSettings::ExtensionSettings(QSettings& settings) : m_Settings(settings) {}
QString ExtensionSettings::path(const IExtension& extension, const Setting& setting)
{
QString path = extension.metadata().identifier();
if (!setting.group().isEmpty()) {
path += "/" + setting.group();
}
return path + "/" + setting.name();
}
bool ExtensionSettings::isEnabled(const MOBase::IExtension& extension,
bool defaultValue) const
{
return get<bool>(m_Settings, EXTENSIONS_ENABLED_GROUP,
extension.metadata().identifier(), defaultValue);
}
void ExtensionSettings::setEnabled(const MOBase::IExtension& extension,
bool enabled) const
{
set(m_Settings, EXTENSIONS_ENABLED_GROUP, extension.metadata().identifier(), enabled);
}
QVariant ExtensionSettings::setting(const IExtension& extension,
const Setting& setting) const
{
return get<QVariant>(m_Settings, EXTENSIONS_GROUP, path(extension, setting),
setting.defaultValue());
}
void ExtensionSettings::setSetting(const IExtension& extension, const Setting& setting,
const QVariant& value)
{
set(m_Settings, EXTENSIONS_GROUP, path(extension, setting), value);
}
// commits all the settings to the ini
//
void ExtensionSettings::save()
{
m_Settings.sync();
}
PluginSettings::PluginSettings(QSettings& settings) : m_Settings(settings) {}
QString PluginSettings::path(const QString& pluginName, const QString& key)
@ -57,7 +103,7 @@ void PluginSettings::fixPluginEnabledSetting(const IPlugin* plugin)
QVariant PluginSettings::setting(const QString& pluginName, const QString& key,
const QVariant& defaultValue) const
{
return get<QVariant>(m_Settings, "Settings", path(pluginName, key), defaultValue);
return get<QVariant>(m_Settings, PLUGINS_GROUP, path(pluginName, key), defaultValue);
}
void PluginSettings::setSetting(const QString& pluginName, const QString& key,

View File

@ -4,8 +4,48 @@
#include <QObject>
#include <QSettings>
#include <uibase/extensions/extension.h>
#include <uibase/iplugin.h>
// settings about extensions
class ExtensionSettings : public QObject
{
Q_OBJECT
public:
ExtensionSettings(QSettings& settings);
// check if the specified extension is enabled in the settings
//
bool isEnabled(const MOBase::IExtension& extension, bool defaultValue = true) const;
// set the extension as enabled or disabled in the settings
//
void setEnabled(const MOBase::IExtension& extension, bool enabled) const;
// returns the plugin setting for the given key
//
QVariant setting(const MOBase::IExtension& extension,
const MOBase::Setting& setting) const;
// sets the plugin setting for the given key
//
void setSetting(const MOBase::IExtension& extension, const MOBase::Setting& setting,
const QVariant& value);
// commits all the settings to the ini
//
void save();
private:
QSettings& m_Settings;
// retrieve the path to the given setting
//
static QString path(const MOBase::IExtension& extension,
const MOBase::Setting& setting);
};
// settings about plugins
//
class PluginSettings : public QObject

View File

@ -704,7 +704,7 @@ std::unique_ptr<Instance> selectInstance()
// since there is no instance currently active, load plugins with a null
// OrganizerCore; see PluginManager::initPlugin()
NexusInterface ni(nullptr);
ExtensionManager ec;
ExtensionManager ec(nullptr);
ec.loadExtensions(QDir(QCoreApplication::applicationDirPath() + "/extensions")
.filesystemAbsolutePath());

View File

@ -215,7 +215,7 @@ int MOApplication::setup(MOMultiProcess& multiProcess, bool forceSelect)
m_themes = std::make_unique<ThemeManager>(this);
m_translations = std::make_unique<TranslationManager>(this);
m_extensions = std::make_unique<ExtensionManager>();
m_extensions = std::make_unique<ExtensionManager>(m_core.get());
m_extensions->registerWatcher(*m_themes);
m_extensions->registerWatcher(*m_translations);

View File

@ -162,11 +162,9 @@ NexusSSOLogin::NexusSSOLogin() : m_keyReceived(false), m_active(false)
onConnected();
});
QObject::connect(&m_socket,
qOverload<QAbstractSocket::SocketError>(&QWebSocket::error),
[&](auto&& e) {
onError(e);
});
QObject::connect(&m_socket, &QWebSocket::errorOccurred, [&](auto&& e) {
onError(e);
});
QObject::connect(&m_socket, &QWebSocket::sslErrors, [&](auto&& errors) {
onSslErrors(errors);

View File

@ -1786,22 +1786,12 @@ Right now the only case I know of where this needs to be overwritten is for the
<translation type="unfinished"></translation>
</message>
<message>
<location filename="settingsdialogextensioninfo.ui" line="121"/>
<location filename="settingsdialogextensioninfo.ui" line="115"/>
<source>Key</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="settingsdialogextensioninfo.ui" line="126"/>
<source>Value</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="settingsdialogextensioninfo.ui" line="134"/>
<source>No plugin found.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="settingsdialogextensioninfo.cpp" line="41"/>
<location filename="settingsdialogextensioninfo.cpp" line="148"/>
<source>Translation and theme extensions cannot be disabled.</source>
<translation type="unfinished"></translation>
</message>
@ -1822,6 +1812,24 @@ Right now the only case I know of where this needs to be overwritten is for the
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ExtensionSettingWidget</name>
<message>
<location filename="settingsdialogextensioninfo.cpp" line="45"/>
<source>False</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="settingsdialogextensioninfo.cpp" line="45"/>
<source>True</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="settingsdialogextensioninfo.cpp" line="77"/>
<source>Edit</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>FileTree</name>
<message>
@ -7382,94 +7390,94 @@ Destination:<byte value="xd"/>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="nxmaccessmanager.cpp" line="192"/>
<location filename="nxmaccessmanager.cpp" line="190"/>
<source>Connecting to Nexus...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="nxmaccessmanager.cpp" line="195"/>
<location filename="nxmaccessmanager.cpp" line="193"/>
<source>Waiting for Nexus...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="nxmaccessmanager.cpp" line="198"/>
<location filename="nxmaccessmanager.cpp" line="196"/>
<source>Opened Nexus in browser.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="nxmaccessmanager.cpp" line="199"/>
<location filename="nxmaccessmanager.cpp" line="197"/>
<source>Switch to your browser and accept the request.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="nxmaccessmanager.cpp" line="202"/>
<location filename="nxmaccessmanager.cpp" line="200"/>
<source>Finished.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="nxmaccessmanager.cpp" line="205"/>
<location filename="nxmaccessmanager.cpp" line="203"/>
<source>No answer from Nexus.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="nxmaccessmanager.cpp" line="206"/>
<location filename="nxmaccessmanager.cpp" line="210"/>
<location filename="nxmaccessmanager.cpp" line="204"/>
<location filename="nxmaccessmanager.cpp" line="208"/>
<source>A firewall might be blocking Mod Organizer.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="nxmaccessmanager.cpp" line="209"/>
<location filename="nxmaccessmanager.cpp" line="207"/>
<source>Nexus closed the connection.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="nxmaccessmanager.cpp" line="213"/>
<location filename="nxmaccessmanager.cpp" line="211"/>
<source>Cancelled.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="nxmaccessmanager.cpp" line="401"/>
<location filename="nxmaccessmanager.cpp" line="399"/>
<source>Failed to request %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="nxmaccessmanager.cpp" line="423"/>
<location filename="nxmaccessmanager.cpp" line="753"/>
<location filename="nxmaccessmanager.cpp" line="421"/>
<location filename="nxmaccessmanager.cpp" line="751"/>
<source>Cancelled</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="nxmaccessmanager.cpp" line="469"/>
<location filename="nxmaccessmanager.cpp" line="467"/>
<source>Internal error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="nxmaccessmanager.cpp" line="504"/>
<location filename="nxmaccessmanager.cpp" line="502"/>
<source>HTTP code %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="nxmaccessmanager.cpp" line="514"/>
<location filename="nxmaccessmanager.cpp" line="512"/>
<source>Invalid JSON</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="nxmaccessmanager.cpp" line="519"/>
<location filename="nxmaccessmanager.cpp" line="517"/>
<source>Bad response</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="nxmaccessmanager.cpp" line="529"/>
<location filename="nxmaccessmanager.cpp" line="527"/>
<source>API key is empty</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="nxmaccessmanager.cpp" line="552"/>
<location filename="nxmaccessmanager.cpp" line="550"/>
<source>SSL error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="nxmaccessmanager.cpp" line="557"/>
<location filename="nxmaccessmanager.cpp" line="555"/>
<source>Timed out</source>
<translation type="unfinished"></translation>
</message>
@ -7537,12 +7545,12 @@ This program is known to cause issues with Mod Organizer, such as freezing or bl
<translation type="unfinished"></translation>
</message>
<message>
<location filename="settings.cpp" line="1750"/>
<location filename="settings.cpp" line="1761"/>
<source>Failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="settings.cpp" line="1751"/>
<location filename="settings.cpp" line="1762"/>
<source>Failed to start the helper application: %1</source>
<translation type="unfinished"></translation>
</message>

View File

@ -73,7 +73,7 @@ PluginDetails::PluginDetails(PluginManager* manager, PluginExtension const& exte
void PluginDetails::fetchRequirements()
{
// m_requirements = m_plugin->requirements();
m_requirements = m_plugin->requirements();
}
std::vector<IPluginRequirement::Problem> PluginDetails::problems() const
@ -133,6 +133,11 @@ PluginManager::PluginManager(ExtensionManager const& manager, OrganizerCore* cor
m_gameFeatures(std::make_unique<GameFeatures>(core, this))
{
m_loaders = makeLoaders();
if (m_core) {
bf::at_key<IPluginDiagnose>(m_plugins).push_back(m_core);
m_core->connectPlugins(this);
}
}
QStringList PluginManager::implementedInterfaces(IPlugin* plugin) const
@ -249,12 +254,7 @@ bool PluginManager::isEnabled(MOBase::IPlugin* plugin) const
return plugin == m_core->managedGame();
}
// check the master of the group
const auto& d = details(plugin);
if (d.master() && d.master() != plugin) {
return isEnabled(d.master());
}
// TODO: allow disabling/enabling plugins alone?
return m_extensions.isEnabled(details(plugin).extension());
}
@ -499,28 +499,12 @@ bool PluginManager::loadPlugins(const MOBase::PluginExtension& extension)
continue;
}
// find the best interface
auto it = std::min_element(std::begin(objectGroup), std::end(objectGroup),
[&](auto const& lhs, auto const& rhs) {
return isBetterInterface(lhs, rhs);
});
IPlugin* master = qobject_cast<IPlugin*>(*it);
// register plugins in the group
for (auto* object : objectGroup) {
IPlugin* plugin = registerPlugin(extension, object, objectGroup);
if (plugin) {
m_details.at(plugin).m_master = master;
}
registerPlugin(extension, object, objectGroup);
}
}
// TODO: move this elsewhere, e.g., in core
if (m_core) {
bf::at_key<IPluginDiagnose>(m_plugins).push_back(m_core);
m_core->connectPlugins(this);
}
return true;
}

View File

@ -48,10 +48,6 @@ public:
//
const auto* proxy() const { return m_organizer; }
// the "master" of the group this plugin belongs to
//
MOBase::IPlugin* master() const { return m_master; }
// the extension containing this plugin
//
const MOBase::PluginExtension& extension() const { return *m_extension; }
@ -79,7 +75,6 @@ private:
PluginManager* m_manager;
MOBase::IPlugin* m_plugin;
const MOBase::PluginExtension* m_extension;
MOBase::IPlugin* m_master;
std::vector<std::shared_ptr<const MOBase::IPluginRequirement>> m_requirements;
OrganizerProxy* m_organizer;

View File

@ -64,9 +64,10 @@ Settings* Settings::s_Instance = nullptr;
Settings::Settings(const QString& path, bool globalInstance)
: m_Settings(path, QSettings::IniFormat), m_Game(m_Settings),
m_Geometry(m_Settings), m_Widgets(m_Settings, globalInstance),
m_Colors(m_Settings), m_Plugins(m_Settings), m_Paths(m_Settings),
m_Network(m_Settings, globalInstance), m_Nexus(*this, m_Settings),
m_Steam(*this, m_Settings), m_Interface(m_Settings), m_Diagnostics(m_Settings)
m_Colors(m_Settings), m_Extensions(m_Settings), m_Plugins(m_Settings),
m_Paths(m_Settings), m_Network(m_Settings, globalInstance),
m_Nexus(*this, m_Settings), m_Steam(*this, m_Settings), m_Interface(m_Settings),
m_Diagnostics(m_Settings)
{
if (globalInstance) {
if (s_Instance != nullptr) {
@ -457,6 +458,16 @@ const ColorSettings& Settings::colors() const
return m_Colors;
}
ExtensionSettings& Settings::extensions()
{
return m_Extensions;
}
const ExtensionSettings& Settings::extensions() const
{
return m_Extensions;
}
PluginSettings& Settings::plugins()
{
return m_Plugins;

View File

@ -768,6 +768,9 @@ public:
ColorSettings& colors();
const ColorSettings& colors() const;
ExtensionSettings& extensions();
const ExtensionSettings& extensions() const;
PluginSettings& plugins();
const PluginSettings& plugins() const;
@ -818,6 +821,7 @@ private:
GeometrySettings m_Geometry;
WidgetSettings m_Widgets;
ColorSettings m_Colors;
ExtensionSettings m_Extensions;
PluginSettings m_Plugins;
PathSettings m_Paths;
NetworkSettings m_Network;

View File

@ -4,10 +4,99 @@
#include <format>
#include <QComboBox>
#include <uibase/formatters.h>
#include "extensionmanager.h"
#include "pluginmanager.h"
#include "settings.h"
using namespace MOBase;
ExtensionSettingWidget::ExtensionSettingWidget(Setting const& setting,
QVariant const& value, QWidget* parent)
: QWidget(parent), m_value(value)
{
setLayout(new QVBoxLayout());
{
auto* titleLabel = new QLabel(setting.title());
auto font = titleLabel->font();
font.setBold(true);
titleLabel->setFont(font);
layout()->addWidget(titleLabel);
}
if (!setting.description().isEmpty()) {
auto* descriptionLabel = new QLabel(setting.description());
auto font = descriptionLabel->font();
font.setItalic(true);
font.setPointSize(static_cast<int>(font.pointSize() * 0.85));
descriptionLabel->setFont(font);
layout()->addWidget(descriptionLabel);
}
{
QWidget* valueWidget = nullptr;
switch (setting.defaultValue().typeId()) {
case QMetaType::Bool: {
auto* comboBox = new QComboBox();
comboBox->addItems({tr("False"), tr("True")});
comboBox->setCurrentIndex(value.toBool());
valueWidget = comboBox;
} break;
case QMetaType::QString: {
auto* lineEdit = new QLineEdit(value.toString());
valueWidget = lineEdit;
} break;
case QMetaType::Float:
case QMetaType::Double: {
auto* lineEdit = new QLineEdit(QString::number(value.toInt()));
lineEdit->setValidator(new QDoubleValidator(lineEdit));
valueWidget = lineEdit;
} break;
case QMetaType::Int:
case QMetaType::LongLong:
case QMetaType::UInt:
case QMetaType::ULongLong: {
auto* lineEdit = new QLineEdit(QString::number(value.toInt()));
lineEdit->setValidator(new QIntValidator(lineEdit));
valueWidget = lineEdit;
} break;
case QMetaType::QColor: {
valueWidget = new QWidget(this);
auto* layout = new QHBoxLayout();
valueWidget->setLayout(layout);
const auto color = m_value.value<QColor>();
auto* textWidget = new QLabel(color.name());
auto* colorWidget = new QLabel("");
colorWidget->setStyleSheet(
QString("QLabel { background-color: %1; }").arg(color.name()));
auto* button = new QPushButton(tr("Edit"));
connect(button, &QPushButton::clicked, [textWidget, colorWidget, this]() {
const auto newColor = QColorDialog::getColor(m_value.value<QColor>());
if (newColor.isValid()) {
m_value = newColor;
textWidget->setText(newColor.name());
colorWidget->setStyleSheet(
QString("QLabel { background-color: %1; }").arg(newColor.name()));
}
});
layout->addWidget(textWidget);
layout->addWidget(colorWidget, 1);
layout->addWidget(button);
} break;
}
if (valueWidget) {
layout()->addWidget(valueWidget);
}
}
}
ExtensionListInfoWidget::ExtensionListInfoWidget(QWidget* parent)
: QWidget(parent), ui{new Ui::ExtensionListInfoWidget()}
{
@ -15,12 +104,30 @@ ExtensionListInfoWidget::ExtensionListInfoWidget(QWidget* parent)
ui->authorLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
ui->authorLabel->setOpenExternalLinks(true);
ui->pluginSettingsList->setRootIsDecorated(true);
ui->pluginSettingsList->setSelectionMode(QAbstractItemView::NoSelection);
ui->pluginSettingsList->setItemsExpandable(true);
ui->pluginSettingsList->setColumnCount(1);
ui->pluginSettingsList->header()->setSectionResizeMode(
0, QHeaderView::ResizeMode::Stretch);
}
void ExtensionListInfoWidget::setup(Settings& settings,
ExtensionManager& extensionManager,
PluginManager& pluginManager)
{
m_settings = &settings;
m_extensionManager = &extensionManager;
m_pluginManager = &pluginManager;
}
void ExtensionListInfoWidget::setExtension(const IExtension& extension)
{
m_extension = &extension;
// update the header for the extension
const auto& metadata = m_extension->metadata();
const auto& author = metadata.author();
@ -40,9 +147,43 @@ void ExtensionListInfoWidget::setExtension(const IExtension& extension)
ui->enabledCheckbox->setToolTip(
tr("Translation and theme extensions cannot be disabled."));
} else {
// TODO:
// ui->enabledCheckbox->setChecked();
ui->enabledCheckbox->setChecked(m_extensionManager->isEnabled(extension));
ui->enabledCheckbox->setEnabled(true);
ui->enabledCheckbox->setToolTip(QString());
}
ui->pluginSettingsList->clear();
// update the list of settings
if (const auto* pluginExtension = dynamic_cast<const PluginExtension*>(m_extension)) {
// TODO: refactor code somewhere to have direct access of the plugins for a given
// extension
for (auto& plugin : m_pluginManager->plugins()) {
if (&m_pluginManager->details(plugin).extension() != m_extension) {
continue;
}
const auto settings = plugin->settings();
if (settings.isEmpty()) {
continue;
}
QTreeWidgetItem* pluginItem = new QTreeWidgetItem({plugin->localizedName()});
ui->pluginSettingsList->addTopLevelItem(pluginItem);
for (auto& setting : settings) {
auto* settingItem = new QTreeWidgetItem();
auto* settingWidget = new ExtensionSettingWidget(
setting, m_settings->plugins().setting(plugin->name(), setting.name(),
setting.defaultValue()));
pluginItem->addChild(settingItem);
ui->pluginSettingsList->setItemWidget(settingItem, 0, settingWidget);
settingItem->setSizeHint(0, settingWidget->sizeHint());
}
pluginItem->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
pluginItem->setExpanded(true);
}
}
}

View File

@ -10,11 +10,31 @@ namespace Ui
class ExtensionListInfoWidget;
}
class ExtensionManager;
class PluginManager;
class Settings;
class ExtensionSettingWidget : public QWidget
{
Q_OBJECT
public:
ExtensionSettingWidget(MOBase::Setting const& setting, QVariant const& value,
QWidget* parent = nullptr);
private:
QVariant m_value;
};
class ExtensionListInfoWidget : public QWidget
{
public:
ExtensionListInfoWidget(QWidget* parent = nullptr);
// setup the widget, should be called before any other functions
//
void setup(Settings& settings, ExtensionManager& extensionManager,
PluginManager& pluginManager);
// set the extension to display
//
void setExtension(const MOBase::IExtension& extension);
@ -22,6 +42,10 @@ public:
private:
Ui::ExtensionListInfoWidget* ui;
Settings* m_settings;
ExtensionManager* m_extensionManager;
PluginManager* m_pluginManager;
// currently displayed extension (default to nullptr)
const MOBase::IExtension* m_extension{nullptr};
};

View File

@ -101,41 +101,20 @@
<property name="indentation">
<number>0</number>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
<property name="headerHidden">
<bool>true</bool>
</property>
<property name="itemsExpandable">
<bool>false</bool>
</property>
<property name="expandsOnDoubleClick">
<bool>false</bool>
<property name="columnCount">
<number>1</number>
</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="QLabel" name="noPluginLabel">
<property name="text">
<string>No plugin found.</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>

View File

@ -17,6 +17,8 @@ ExtensionsSettingsTab::ExtensionsSettingsTab(Settings& s,
: SettingsTab(s, d), m_extensionManager(&extensionManager),
m_pluginManager(&pluginManager)
{
ui->infoWidget->setup(s, extensionManager, pluginManager);
// TODO: use Qt system to sort extensions instead of sorting beforehand
std::vector<const IExtension*> extensions;
for (auto& extension : m_extensionManager->extensions()) {

View File

@ -464,7 +464,7 @@ TextEditorToolbar::TextEditorToolbar(TextEditor& editor)
m_save = new QAction(QIcon(":/MO/gui/save"), QObject::tr("&Save"), &editor);
m_save->setShortcutContext(Qt::WidgetWithChildrenShortcut);
m_save->setShortcut(Qt::CTRL + Qt::Key_S);
m_save->setShortcut(Qt::CTRL | Qt::Key_S);
m_editor.addAction(m_save);
m_wordWrap =

View File

@ -47,7 +47,7 @@ void TranslationManager::addOldFormatTranslations()
QString languageString = QString("%1 (%2)")
.arg(locale.nativeLanguageName())
.arg(locale.nativeCountryName());
.arg(locale.nativeTerritoryName());
if (locale.language() == QLocale::Chinese) {
if (languageCode == "zh_TW") {