feat: 增加插件管理者插件支持以及引入相关破坏性更新;

This commit is contained in:
寂静的羽夏 2025-06-26 19:45:55 +08:00
parent 08d5969070
commit b42880aa7e
39 changed files with 1042 additions and 795 deletions

View File

@ -28,6 +28,7 @@ add_definitions(-DAS_NO_THREADS)
if(BUILD_TEST_PLUGIN)
add_subdirectory(TestPlugin)
add_subdirectory(TestManager)
endif()
if(BUILD_SHARED_MEM_EXT)

View File

@ -1,5 +1,6 @@
{
"Id" : "shmem",
"SDK": 18,
"Version" : "0.0.1",
"Vendor" : "WingCloudStudio",
"Author" : "wingsummer",

View File

@ -4,27 +4,27 @@
<context>
<name>SharedMemoryDriver</name>
<message>
<location filename="../sharememorydrv.cpp" line="38"/>
<location filename="../sharememorydrv.cpp" line="36"/>
<source>SharedMemoryDriver</source>
<translation></translation>
</message>
<message>
<location filename="../sharememorydrv.cpp" line="42"/>
<location filename="../sharememorydrv.cpp" line="40"/>
<source>An extension for opening sshared memory in WingHexExplorer2.</source>
<translation>2</translation>
</message>
<message>
<location filename="../sharememorydrv.cpp" line="62"/>
<location filename="../sharememorydrv.cpp" line="56"/>
<source>ShareMemory</source>
<translation></translation>
</message>
<message>
<location filename="../sharememorydrv.cpp" line="71"/>
<location filename="../sharememorydrv.cpp" line="65"/>
<source>SharedMemory</source>
<translation></translation>
</message>
<message>
<location filename="../sharememorydrv.cpp" line="71"/>
<location filename="../sharememorydrv.cpp" line="65"/>
<source>PleaseInputID:</source>
<translation></translation>
</message>

View File

@ -23,8 +23,6 @@ SharedMemoryDriver::SharedMemoryDriver() : WingHex::IWingDevice() {}
SharedMemoryDriver::~SharedMemoryDriver() {}
int SharedMemoryDriver::sdkVersion() const { return WingHex::SDKVERSION; }
bool SharedMemoryDriver::init(const std::unique_ptr<QSettings> &set) {
Q_UNUSED(set);
return true;
@ -42,10 +40,6 @@ const QString SharedMemoryDriver::pluginComment() const {
return tr("An extension for opening sshared memory in WingHexExplorer2.");
}
QList<WingHex::PluginPage *> SharedMemoryDriver::registeredPages() const {
return _plgps;
}
WingHex::WingIODevice *SharedMemoryDriver::onOpenFile(const QString &path) {
return new SharedMemory(path, SharedMemory::ReadWrite, this);
}

View File

@ -34,15 +34,11 @@ public:
// IWingPlugin interface
public:
virtual int sdkVersion() const override;
virtual bool init(const std::unique_ptr<QSettings> &set) override;
virtual void unload(std::unique_ptr<QSettings> &set) override;
virtual const QString pluginName() const override;
virtual const QString pluginComment() const override;
public:
virtual QList<WingHex::PluginPage *> registeredPages() const override;
// IWingDevice interface
public:
virtual QString onOpenFileBegin() override;
@ -50,9 +46,6 @@ public:
virtual QIcon supportedFileIcon() const override;
virtual WingHex::WingIODevice *onOpenFile(const QString &path) override;
virtual bool onCloseFile(WingHex::WingIODevice *dev) override;
private:
QList<WingHex::PluginPage *> _plgps;
};
#endif // SHAREDMEMORYDRIVER_H

View File

@ -0,0 +1,50 @@
cmake_minimum_required(VERSION 3.16)
project(TestManager)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_INCLUDE_CURRENT_DIR TRUE)
# Test mode, please configure the main program directory to facilitate debugging
# 便
# vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
option(TEST_MODE TRUE)
# For Qt
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)
find_package(
Qt${QT_VERSION_MAJOR}
COMPONENTS Widgets
REQUIRED)
add_library(TestManager SHARED testmanager.h testmanager.cpp TestManager.json)
set_target_properties(TestManager PROPERTIES SUFFIX ".wingman")
if(TEST_MODE)
# If you want to be able to debug easily every time you compile, please set
# this variable. Because this test plugin is a subproject of the main
# project, use CMAKE_BINARY_DIR
# 便 CMAKE_BINARY_DIR
# vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
set(WINGHEX_PATH "${CMAKE_BINARY_DIR}")
add_custom_command(
TARGET TestManager
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:TestManager> ${WINGHEX_PATH})
endif()
target_link_libraries(TestManager PRIVATE Qt${QT_VERSION_MAJOR}::Widgets
WingPlugin)

View File

@ -0,0 +1,9 @@
{
"Id": "TestManager",
"SDK": 18,
"Version": "0.0.1",
"Vendor": "WingCloudStudio",
"Author": "wingsummer",
"License": "AGPL-3.0",
"Url": "https://github.com/Wing-summer/WingHexExplorer2"
}

View File

@ -18,21 +18,40 @@
** =============================================================================
*/
#include "testpluginpage.h"
#include "testmanager.h"
#include <QVBoxLayout>
TestManager::TestManager() : WingHex::IWingManager() { content = new TestPage; }
TestPluginPage::TestPluginPage(QWidget *parent) : WingHex::PluginPage(parent) {
auto layout = new QVBoxLayout(this);
_lbl = new QLabel(QStringLiteral("TestPluginPage"), this);
_lbl->setAlignment(Qt::AlignCenter);
layout->addWidget(_lbl);
TestManager::~TestManager() {
// no need to manual delete content
// the host will take the ownership
}
QIcon TestPluginPage::categoryIcon() const {
return QIcon(QStringLiteral(":/images/TestPlugin/images/btn.png"));
bool TestManager::init(const std::unique_ptr<QSettings> &set) {
Q_UNUSED(set);
return true;
}
QString TestPluginPage::name() const { return tr("TestPluginPage"); }
void TestManager::unload(std::unique_ptr<QSettings> &set) { Q_UNUSED(set); }
QString TestPluginPage::id() const { return QStringLiteral("TestPluginPage"); }
const QString TestManager::comment() const {
return QStringLiteral("Hello world!");
}
QList<WingHex::SettingPage *> TestManager::registeredSettingPages() const {
return {content};
}
bool TestManager::enterGuard(const QMetaObject *sender, const QString &sig,
const QVariantList &params) {
if (content->isDisableMsg()) {
if (sig.startsWith("msg")) {
// block all msg-prefix function
logWarn(QStringLiteral("Blocking: (%1) {%2}")
.arg(sender->className(), sig));
return false;
}
}
return true;
}

98
TestManager/testmanager.h Normal file
View File

@ -0,0 +1,98 @@
/*==============================================================================
** Copyright (C) 2024-2027 WingSummer
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and associated documentation files (the "Software"), to deal
** in the Software without restriction, including without limitation the rights
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
** copies of the Software, and to permit persons to whom the Software is
** furnished to do so.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
** THE SOFTWARE.
** =============================================================================
*/
#ifndef TESTMANAGER_H
#define TESTMANAGER_H
#include "WingPlugin/iwingmanager.h"
#include <QCheckBox>
#include <QVBoxLayout>
class TestManager : public WingHex::IWingManager {
Q_OBJECT
// 这两行是必须,只有后面的 "TestManager.json" 你根据需要修改,
// 具体可见 QT 文档,剩下直接 CV 大法
Q_PLUGIN_METADATA(IID "com.wingsummer.iwingmanager" FILE "TestManager.json")
Q_INTERFACES(WingHex::IWingManager)
public:
explicit TestManager();
virtual ~TestManager();
// IWingPluginCoreBase interface
public:
virtual bool init(const std::unique_ptr<QSettings> &set) override;
virtual void unload(std::unique_ptr<QSettings> &set) override;
public:
virtual const QString comment() const override;
virtual QList<WingHex::SettingPage *>
registeredSettingPages() const override;
private:
class TestPage : public WingHex::SettingPage {
public:
TestPage() {
auto layout = new QVBoxLayout(this);
_cbblk = new QCheckBox(QStringLiteral("Disable msg*"), this);
_cbblk->setChecked(false);
layout->addWidget(_cbblk);
layout->addStretch();
}
// PageBase interface
public:
virtual QIcon categoryIcon() const override {
return QIcon(WingHex::HOSTRESPIMG("monitor"));
}
virtual QString name() const override {
return QStringLiteral("TestManager");
}
virtual QString id() const override {
return QStringLiteral("TestManager");
}
// SettingInterface interface
public:
virtual void apply() override { _isDisabled = _cbblk->isChecked(); }
virtual void reset() override {
_isDisabled = false;
_cbblk->setChecked(false);
}
virtual void cancel() override { _cbblk->setChecked(_isDisabled); }
public:
bool isDisableMsg() const { return _isDisabled; }
private:
QCheckBox *_cbblk;
bool _isDisabled = false;
};
public slots:
virtual bool enterGuard(const QMetaObject *sender, const QString &sig,
const QVariantList &params) override;
private:
TestPage *content;
};
#endif // TESTMANAGER_H

View File

@ -64,9 +64,7 @@ add_library(
testsettingpage.h
testsettingpage.cpp
testwingeditorviewwidget.h
testwingeditorviewwidget.cpp
testpluginpage.h
testpluginpage.cpp)
testwingeditorviewwidget.cpp)
set_target_properties(TestPlugin PROPERTIES SUFFIX ".wingplg")

View File

@ -1,5 +1,6 @@
{
"Id": "TestPlugin",
"SDK": 18,
"Version": "0.0.1",
"Vendor": "WingCloudStudio",
"Dependencies": [

View File

@ -269,72 +269,64 @@
<context>
<name>TestPlugin</name>
<message>
<location filename="../testplugin.cpp" line="207"/>
<location filename="../testplugin.cpp" line="204"/>
<source>Test</source>
<translation></translation>
</message>
<message>
<location filename="../testplugin.cpp" line="219"/>
<location filename="../testplugin.cpp" line="228"/>
<location filename="../testplugin.cpp" line="233"/>
<location filename="../testplugin.cpp" line="314"/>
<location filename="../testplugin.cpp" line="216"/>
<location filename="../testplugin.cpp" line="225"/>
<location filename="../testplugin.cpp" line="230"/>
<location filename="../testplugin.cpp" line="299"/>
<source>TestPlugin</source>
<translation></translation>
</message>
<message>
<location filename="../testplugin.cpp" line="237"/>
<location filename="../testplugin.cpp" line="234"/>
<source>Button - </source>
<translation> - </translation>
</message>
<message>
<location filename="../testplugin.cpp" line="241"/>
<location filename="../testplugin.cpp" line="238"/>
<source>Click</source>
<translation></translation>
</message>
<message>
<location filename="../testplugin.cpp" line="317"/>
<location filename="../testplugin.cpp" line="302"/>
<source>A Test Plugin for WingHexExplorer2.</source>
<translation>2</translation>
</message>
<message>
<location filename="../testplugin.cpp" line="355"/>
<location filename="../testplugin.cpp" line="363"/>
<location filename="../testplugin.cpp" line="372"/>
<location filename="../testplugin.cpp" line="393"/>
<location filename="../testplugin.cpp" line="409"/>
<location filename="../testplugin.cpp" line="416"/>
<location filename="../testplugin.cpp" line="423"/>
<location filename="../testplugin.cpp" line="430"/>
<location filename="../testplugin.cpp" line="438"/>
<location filename="../testplugin.cpp" line="467"/>
<location filename="../testplugin.cpp" line="475"/>
<location filename="../testplugin.cpp" line="483"/>
<location filename="../testplugin.cpp" line="491"/>
<location filename="../testplugin.cpp" line="500"/>
<location filename="../testplugin.cpp" line="507"/>
<location filename="../testplugin.cpp" line="336"/>
<location filename="../testplugin.cpp" line="344"/>
<location filename="../testplugin.cpp" line="353"/>
<location filename="../testplugin.cpp" line="374"/>
<location filename="../testplugin.cpp" line="390"/>
<location filename="../testplugin.cpp" line="397"/>
<location filename="../testplugin.cpp" line="404"/>
<location filename="../testplugin.cpp" line="411"/>
<location filename="../testplugin.cpp" line="419"/>
<location filename="../testplugin.cpp" line="448"/>
<location filename="../testplugin.cpp" line="456"/>
<location filename="../testplugin.cpp" line="464"/>
<location filename="../testplugin.cpp" line="472"/>
<location filename="../testplugin.cpp" line="481"/>
<location filename="../testplugin.cpp" line="488"/>
<source>InvalidParamsCount</source>
<translation></translation>
</message>
<message>
<location filename="../testplugin.cpp" line="386"/>
<location filename="../testplugin.cpp" line="402"/>
<location filename="../testplugin.cpp" line="367"/>
<location filename="../testplugin.cpp" line="383"/>
<source>InvalidParam</source>
<translation></translation>
</message>
<message>
<location filename="../testplugin.cpp" line="458"/>
<location filename="../testplugin.cpp" line="439"/>
<source>AllocArrayFailed</source>
<translation></translation>
</message>
</context>
<context>
<name>TestPluginPage</name>
<message>
<location filename="../testpluginpage.cpp" line="36"/>
<source>TestPluginPage</source>
<translation></translation>
</message>
</context>
<context>
<name>TestWingEditorViewWidget</name>
<message>

View File

@ -20,7 +20,6 @@
#include "testplugin.h"
#include "testform.h"
#include "testpluginpage.h"
#include "testsettingpage.h"
#include "testwingeditorviewwidget.h"
@ -180,8 +179,6 @@ TestPlugin::TestPlugin() : WingHex::IWingPlugin() {
TestPlugin::~TestPlugin() { destoryTestShareMem(); }
int TestPlugin::sdkVersion() const { return WingHex::SDKVERSION; }
bool TestPlugin::init(const std::unique_ptr<QSettings> &set) {
auto v = set->value("Test", 0).toInt();
// 如果你之前启动过且正常推出,这个值一定是 5
@ -247,17 +244,11 @@ bool TestPlugin::init(const std::unique_ptr<QSettings> &set) {
_rtbinfo.append(rtinfo);
}
{
auto sp = new TestSettingPage(QStringLiteral("Test1"),
QStringLiteral("This is a Test1"));
_setpages.insert(sp, true);
}
_setpages.append(new TestSettingPage(
QStringLiteral("Test1"), QStringLiteral("This is a Test1"), true));
{
auto sp = new TestSettingPage(QStringLiteral("Test2"),
QStringLiteral("This is a Test2"));
_setpages.insert(sp, false);
}
_setpages.append(new TestSettingPage(
QStringLiteral("Test2"), QStringLiteral("This is a Test2"), false));
{
WingHex::WingDockWidgetInfo info;
@ -274,11 +265,6 @@ bool TestPlugin::init(const std::unique_ptr<QSettings> &set) {
_evws.append(ev);
}
{
auto pp = new TestPluginPage;
_plgps.append(pp);
}
_tmenu = new QMenu(QStringLiteral("TestPlugin"));
auto micon = QIcon(QStringLiteral(":/images/TestPlugin/images/btn.png"));
_tmenu->setIcon(micon);
@ -298,9 +284,8 @@ void TestPlugin::unload(std::unique_ptr<QSettings> &set) {
// 设个数字,那就是 5 测试一下配置是否正常工作
set->setValue("Test", 5);
for (auto p = _setpages.constKeyValueBegin();
p != _setpages.constKeyValueEnd(); ++p) {
p->first->deleteLater();
for (auto &p : _setpages) {
p->deleteLater();
}
for (auto &item : _winfo) {
@ -332,14 +317,10 @@ TestPlugin::registeredRibbonTools() const {
return _rtbinfo;
}
QHash<WingHex::SettingPage *, bool> TestPlugin::registeredSettingPages() const {
QList<WingHex::SettingPage *> TestPlugin::registeredSettingPages() const {
return _setpages;
}
QList<WingHex::PluginPage *> TestPlugin::registeredPages() const {
return _plgps;
}
QList<QSharedPointer<WingHex::WingEditorViewWidget::Creator>>
TestPlugin::registeredEditorViewWidgets() const {
return _evws;

View File

@ -40,7 +40,6 @@ public:
// IWingPlugin interface (必须)
public:
virtual int sdkVersion() const override;
virtual bool init(const std::unique_ptr<QSettings> &set) override;
virtual void unload(std::unique_ptr<QSettings> &set) override;
virtual const QString pluginName() const override;
@ -57,9 +56,8 @@ public:
virtual QMenu *registeredHexContextMenu() const override;
virtual QList<WingHex::WingRibbonToolBoxInfo>
registeredRibbonTools() const override;
virtual QHash<WingHex::SettingPage *, bool>
virtual QList<WingHex::SettingPage *>
registeredSettingPages() const override;
virtual QList<WingHex::PluginPage *> registeredPages() const override;
virtual QList<QSharedPointer<WingHex::WingEditorViewWidget::Creator>>
registeredEditorViewWidgets() const override;
virtual QHash<QString, ScriptFnInfo> registeredScriptFns() const override;
@ -124,9 +122,8 @@ private:
QHash<QString, WingHex::IWingPlugin::ScriptFnInfo> _scriptInfo;
QList<WingHex::WingDockWidgetInfo> _winfo;
QList<WingHex::WingRibbonToolBoxInfo> _rtbinfo;
QHash<WingHex::SettingPage *, bool> _setpages;
QList<WingHex::SettingPage *> _setpages;
QList<QSharedPointer<WingHex::WingEditorViewWidget::Creator>> _evws;
QList<WingHex::PluginPage *> _plgps;
QHash<QString, WingHex::IWingPlugin::UNSAFE_SCFNPTR> _scriptUnsafe;
};

View File

@ -1,43 +0,0 @@
/*==============================================================================
** Copyright (C) 2024-2027 WingSummer
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and associated documentation files (the "Software"), to deal
** in the Software without restriction, including without limitation the rights
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
** copies of the Software, and to permit persons to whom the Software is
** furnished to do so.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
** THE SOFTWARE.
** =============================================================================
*/
#ifndef TESTPLUGINPAGE_H
#define TESTPLUGINPAGE_H
#include "WingPlugin/settingpage.h"
#include <QLabel>
class TestPluginPage : public WingHex::PluginPage {
Q_OBJECT
public:
explicit TestPluginPage(QWidget *parent = nullptr);
// PageBase interface
public:
virtual QIcon categoryIcon() const override;
virtual QString name() const override;
virtual QString id() const override;
private:
QLabel *_lbl = nullptr;
};
#endif // TESTPLUGINPAGE_H

View File

@ -23,8 +23,8 @@
#include <QVBoxLayout>
TestSettingPage::TestSettingPage(const QString &id, const QString &content,
QWidget *parent)
: WingHex::SettingPage(parent), _id(id) {
bool isShowInRibbon, QWidget *parent)
: WingHex::SettingPage(parent), _id(id), _isShownInRibbton(isShowInRibbon) {
auto layout = new QVBoxLayout(this);
_lbl = new QLabel(content, this);
_lbl->setAlignment(Qt::AlignCenter);
@ -39,6 +39,8 @@ QString TestSettingPage::name() const { return _id; }
QString TestSettingPage::id() const { return _id; }
bool TestSettingPage::showInRibbon() const { return _isShownInRibbton; }
void TestSettingPage::apply() {}
void TestSettingPage::reset() {}

View File

@ -29,7 +29,7 @@ class TestSettingPage : public WingHex::SettingPage {
Q_OBJECT
public:
explicit TestSettingPage(const QString &id, const QString &content,
QWidget *parent = nullptr);
bool isShowInRibbon, QWidget *parent = nullptr);
// PageBase interface
public:
@ -37,6 +37,8 @@ public:
virtual QString name() const override;
virtual QString id() const override;
virtual bool showInRibbon() const override;
// SettingPage interface
public:
virtual void apply() override;
@ -45,7 +47,7 @@ public:
private:
QLabel *_lbl = nullptr;
bool _isShownInRibbton;
QString _id;
};

@ -1 +1 @@
Subproject commit ad5654088ab1da66ad93713ef5933a603fb8e2a3
Subproject commit ec5bcd41309e175aa262f367011c1ad9fe7e9b31

View File

@ -68,7 +68,7 @@ BEGIN
BLOCK "080404b0"
BEGIN
VALUE "CompanyName", "ÓðÔÆ¹¤×÷ÊÒ£¨WingCloudStudio£©"
VALUE "FileDescription", "一个自由强大跨平台的十六进制编辑器"
VALUE "FileDescription", "羽云十六进制编辑器"
VALUE "FileVersion", "1.0.0"
VALUE "InternalName", "WingHexExplorer2.exe"
VALUE "LegalCopyright", "AGPL-3.0"

BIN
images/monitor.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -61,6 +61,7 @@
<file>images/metadatah.png</file>
<file>images/metahide.png</file>
<file>images/metashow.png</file>
<file>images/monitor.png</file>
<file>images/new.png</file>
<file>images/open.png</file>
<file>images/openapp.png</file>

View File

@ -1,5 +1,6 @@
{
"Id": "WingAngelAPI",
"SDK": 18,
"Author": "wingsummer",
"Version": "2.2.2",
"Vendor": "WingCloudStudio",

View File

@ -1,5 +1,6 @@
{
"Id" : "WingCStruct",
"SDK": 18,
"Version" : "0.0.2",
"Vendor" : "WingCloudStudio",
"Author" : "wingsummer",

View File

@ -2520,6 +2520,12 @@ bool PluginSystem::checkErrAllAllowAndReport(const QObject *sender,
return false;
}
const std::optional<PluginInfo> &PluginSystem::monitorManagerInfo() const {
return _manInfo;
}
IWingManager *PluginSystem::monitorManager() const { return _manager; }
IWingPlugin *PluginSystem::checkPluginAndReport(const QObject *sender,
const char *func) {
Q_ASSERT(func);
@ -3075,8 +3081,8 @@ IWingDevice *PluginSystem::device(qsizetype index) const {
}
template <typename T>
std::optional<PluginSystem::PluginInfo>
PluginSystem::loadPlugin(const QFileInfo &fileinfo, const QDir &setdir) {
std::optional<PluginInfo> PluginSystem::loadPlugin(const QFileInfo &fileinfo,
const QDir &setdir) {
Q_ASSERT(_win);
if (fileinfo.exists()) {
@ -3090,7 +3096,7 @@ PluginSystem::loadPlugin(const QFileInfo &fileinfo, const QDir &setdir) {
auto lmeta = loader.metaData();
PluginStatus cret;
std::optional<PluginSystem::PluginInfo> meta;
std::optional<PluginInfo> meta;
if (lmeta.contains("MetaData")) {
auto m = parsePluginMetadata(lmeta["MetaData"].toObject());
cret = checkPluginMetadata(m, std::is_same_v<T, IWingPlugin>);
@ -3116,13 +3122,25 @@ PluginSystem::loadPlugin(const QFileInfo &fileinfo, const QDir &setdir) {
case PluginStatus::DupID:
Logger::critical(tr("InvalidDupPlugin"));
return std::nullopt;
case PluginStatus::SDKVersion:
Logger::critical(tr("ErrLoadPluginSDKVersion"));
return std::nullopt;
}
auto m = meta.value();
if (_manager) {
if (!_manager->onLoadingPlugin(fileName, m)) {
Logger::critical(QStringLiteral("{ ") + m.id +
QStringLiteral("} ") +
tr("PluginBlockByManager"));
return std::nullopt;
}
}
auto p = qobject_cast<T *>(loader.instance());
if (Q_UNLIKELY(p == nullptr)) {
Logger::critical(loader.errorString());
} else {
auto m = meta.value();
retranslateMetadata(p, m);
loadPlugin(p, m, setdir);
}
@ -3196,11 +3214,11 @@ PluginSystem::assginHandleForPluginView(IWingPlugin *plg, EditorView *view) {
return id;
}
PluginSystem::PluginInfo
PluginSystem::parsePluginMetadata(const QJsonObject &meta) {
PluginSystem::PluginInfo info;
PluginInfo PluginSystem::parsePluginMetadata(const QJsonObject &meta) {
PluginInfo info;
info.id = meta["Id"].toString().trimmed();
info.SDKVersion = meta["SDK"].toInt();
info.version =
QVersionNumber::fromString(meta["Version"].toString().trimmed());
@ -3238,6 +3256,10 @@ PluginSystem::PluginStatus
PluginSystem::checkPluginMetadata(const PluginInfo &meta, bool isPlg) {
constexpr auto puid_limit = 36; // same as uuid length, so enough
if (meta.SDKVersion != SDKVERSION) {
return PluginStatus::SDKVersion;
}
if (meta.id.length() > puid_limit) {
return PluginStatus::InvalidID;
}
@ -3560,8 +3582,7 @@ IWingDevice *PluginSystem::ext2Device(const QString &ext) {
return *r;
}
PluginSystem::PluginInfo
PluginSystem::getPluginInfo(IWingPluginBase *plg) const {
PluginInfo PluginSystem::getPluginInfo(IWingPluginBase *plg) const {
Q_ASSERT(plg);
return _pinfos.value(plg);
}
@ -3596,7 +3617,7 @@ void PluginSystem::loadExtPlugin() {
loadPlugin<IWingPlugin>(item, udir);
}
QList<PluginSystem::PluginInfo> errorplg;
QList<PluginInfo> errorplg;
if (!_lazyplgs.isEmpty()) {
QStringList lazyplgs;
lazyplgs.swap(_lazyplgs);
@ -3687,18 +3708,59 @@ void PluginSystem::try2LoadManagerPlugin() {
auto lmeta = loader.metaData();
auto m = parsePluginMetadata(lmeta["MetaData"].toObject());
// ID should not be empty
if (m.id.isEmpty()) {
auto cret = checkPluginMetadata(m, false);
switch (cret) {
case PluginStatus::Valid:
break;
case PluginStatus::SDKVersion:
Logger::critical(tr("ErrLoadPluginSDKVersion"));
return;
case PluginStatus::InvalidID:
Logger::critical(tr("InvalidPluginID"));
return;
case PluginStatus::BrokenVersion:
Logger::critical(tr("InvalidPluginBrokenInfo"));
return;
case PluginStatus::DupID:
case PluginStatus::LackDependencies:
// monitor is the first plugin to load and
// should not have any dependency
Q_ASSERT(false);
return;
}
auto p = qobject_cast<IWingManager *>(loader.instance());
if (p) {
QDir udir(Utilities::getAppDataPath());
auto plgset = QStringLiteral("plgset");
udir.mkdir(plgset);
if (!udir.cd(plgset)) {
throw CrashCode::PluginSetting;
}
auto setp = std::make_unique<QSettings>(udir.absoluteFilePath(m.id),
QSettings::Format::IniFormat);
if (!p->init(setp)) {
setp->deleteLater();
Logger::critical(tr("ErrLoadInitPlugin"));
return;
}
applyFunctionTables(p, _plgFns);
_manager = p;
// translate the meta-data
m.author = p->retranslate(m.author);
m.vendor = p->retranslate(m.vendor);
m.license = p->retranslate(m.license);
_manInfo = m;
// TODO
registerRibbonTools(p->registeredRibbonTools());
registeredSettingPages(QVariant::fromValue(p),
p->registeredSettingPages());
}
}
@ -4160,10 +4222,6 @@ void PluginSystem::loadPlugin(IWingPlugin *p, PluginInfo &meta,
QTranslator *p_tr = nullptr;
try {
if (p->sdkVersion() != SDKVERSION) {
throw tr("ErrLoadPluginSDKVersion");
}
if (!p->pluginName().trimmed().length()) {
throw tr("ErrLoadPluginNoName");
}
@ -4193,61 +4251,12 @@ void PluginSystem::loadPlugin(IWingPlugin *p, PluginInfo &meta,
_loadedplgs.append(p);
_pinfos.insert(p, meta);
Logger::warning(tr("PluginName :") + p->pluginName());
Logger::warning(tr("PluginAuthor :") + meta.author);
Logger::warning(tr("PluginWidgetRegister"));
Logger::info(tr("PluginName :") + p->pluginName());
Logger::debug(tr("PluginAuthor :") + meta.author);
Logger::debug(tr("PluginWidgetRegister"));
// ensure call only once
auto ribbonToolboxInfos = p->registeredRibbonTools();
if (!ribbonToolboxInfos.isEmpty()) {
for (auto &item : ribbonToolboxInfos) {
if (_win->m_ribbonMaps.contains(item.catagory)) {
if (!item.toolboxs.isEmpty()) {
auto &cat = _win->m_ribbonMaps[item.catagory];
for (auto &group : item.toolboxs) {
if (group.tools.isEmpty()) {
continue;
}
auto g = cat->addGroup(group.name);
for (auto &tool : group.tools) {
g->addButton(tool);
}
}
}
} else {
if (!item.toolboxs.isEmpty()) {
bool isSys = false;
RibbonTabContent *cat;
if (_win->m_ribbonMaps.contains(item.catagory)) {
isSys = true;
cat = _win->m_ribbonMaps.value(item.catagory);
} else {
cat = new RibbonTabContent;
}
bool hasAdded = false;
for (auto &group : item.toolboxs) {
if (group.tools.isEmpty()) {
continue;
}
auto g = cat->addGroup(group.name);
for (auto &tool : group.tools) {
g->addButton(tool);
}
hasAdded = true;
}
if (!isSys) {
if (hasAdded) {
_win->m_ribbon->addTab(cat, item.displayName);
_win->m_ribbonMaps[item.catagory] = cat;
} else {
delete cat;
}
}
}
}
}
}
registerRibbonTools(p->registeredRibbonTools());
registerPluginDockWidgets(p);
{
@ -4264,18 +4273,8 @@ void PluginSystem::loadPlugin(IWingPlugin *p, PluginInfo &meta,
}
}
{
auto sp = p->registeredSettingPages();
if (!sp.isEmpty()) {
for (auto page = sp.keyBegin(); page != sp.keyEnd(); ++page) {
auto pp = *page;
pp->setProperty("__plg__", QVariant::fromValue(p));
}
_win->m_settingPages.insert(sp);
}
}
registerPluginPages(p);
registeredSettingPages(QVariant::fromValue(p),
p->registeredSettingPages());
registerFns(p);
registerEnums(p);
@ -4298,12 +4297,8 @@ void PluginSystem::loadPlugin(IWingDevice *p, PluginInfo &meta,
QTranslator *p_tr = nullptr;
try {
if (p->sdkVersion() != SDKVERSION) {
throw tr("ErrLoadExtPluginSDKVersion");
}
Logger::warning(tr("ExtPluginAuthor :") + meta.author);
Logger::warning(tr("ExtPluginWidgetRegister"));
Logger::debug(tr("ExtPluginAuthor :") + meta.author);
Logger::debug(tr("ExtPluginWidgetRegister"));
p_tr = LanguageManager::instance().try2LoadPluginLang(meta.id);
@ -4326,7 +4321,6 @@ void PluginSystem::loadPlugin(IWingDevice *p, PluginInfo &meta,
_loadeddevs.append(p);
_pinfos.insert(p, meta);
registerPluginPages(p);
registerMarcoDevice(p);
// ok register into menu open
@ -4454,22 +4448,74 @@ void PluginSystem::registerPluginDockWidgets(IWingPluginBase *p) {
}
}
void PluginSystem::registerPluginPages(IWingPluginBase *p) {
auto rp = p->registeredPages();
if (!rp.isEmpty()) {
for (auto &page : rp) {
page->setProperty("__plg__", QVariant::fromValue(p));
}
_win->m_plgPages.append(rp);
}
}
void PluginSystem::registerMarcoDevice(IWingDevice *plg) {
auto id = getPUID(plg).toUpper();
auto sep = QStringLiteral("_");
_scriptMarcos.append(sep + id + sep);
}
void PluginSystem::registerRibbonTools(
const QList<WingRibbonToolBoxInfo> &tools) {
if (!tools.isEmpty()) {
for (auto &item : tools) {
if (_win->m_ribbonMaps.contains(item.catagory)) {
if (!item.toolboxs.isEmpty()) {
auto &cat = _win->m_ribbonMaps[item.catagory];
for (auto &group : item.toolboxs) {
if (group.tools.isEmpty()) {
continue;
}
auto g = cat->addGroup(group.name);
for (auto &tool : group.tools) {
g->addButton(tool);
}
}
}
} else {
if (!item.toolboxs.isEmpty()) {
bool isSys = false;
RibbonTabContent *cat;
if (_win->m_ribbonMaps.contains(item.catagory)) {
isSys = true;
cat = _win->m_ribbonMaps.value(item.catagory);
} else {
cat = new RibbonTabContent;
}
bool hasAdded = false;
for (auto &group : item.toolboxs) {
if (group.tools.isEmpty()) {
continue;
}
auto g = cat->addGroup(group.name);
for (auto &tool : group.tools) {
g->addButton(tool);
}
hasAdded = true;
}
if (!isSys) {
if (hasAdded) {
_win->m_ribbon->addTab(cat, item.displayName);
_win->m_ribbonMaps[item.catagory] = cat;
} else {
delete cat;
}
}
}
}
}
}
}
void PluginSystem::registeredSettingPages(const QVariant &itptr,
const QList<SettingPage *> &pages) {
if (!pages.isEmpty()) {
for (auto &page : pages) {
page->setProperty("__plg__", itptr);
}
_win->m_settingPages.append(pages);
}
}
bool PluginSystem::checkThreadAff() {
if (QThread::currentThread() != qApp->thread()) {
Logger::warning(tr("Not allowed operation in non-UI thread"));
@ -4497,6 +4543,7 @@ void PluginSystem::loadAllPlugin() {
try2LoadManagerPlugin();
auto &set = SettingManager::instance();
// manager plugin can not block WingAngelAPI, only settings
if (set.scriptEnabled()) {
_angelplg = new WingAngelAPI;
@ -4520,7 +4567,6 @@ void PluginSystem::loadAllPlugin() {
initCheckingEngine();
{
auto cstructplg = new WingCStruct;
QFile cstructjson(QStringLiteral(
":/com.wingsummer.winghex/src/class/WingCStruct.json"));
auto ret = cstructjson.open(QFile::ReadOnly);
@ -4532,16 +4578,23 @@ void PluginSystem::loadAllPlugin() {
QJsonDocument doc = QJsonDocument::fromJson(cstruct);
auto meta = parsePluginMetadata(doc.object());
QDir setd(Utilities::getAppDataPath());
auto plgset = QStringLiteral("plgset");
setd.mkdir(plgset);
retranslateMetadata(cstructplg, meta);
loadPlugin(cstructplg, meta, setd);
// internal plugin has no filename
if (_manager->onLoadingPlugin({}, meta)) {
auto cstructplg = new WingCStruct;
QDir setd(Utilities::getAppDataPath());
auto plgset = QStringLiteral("plgset");
setd.mkdir(plgset);
retranslateMetadata(cstructplg, meta);
loadPlugin(cstructplg, meta, setd);
} else {
Logger::critical(QStringLiteral("{ ") + meta.id +
QStringLiteral("} ") + tr("PluginBlockByManager"));
}
}
Logger::newLine();
bool ok;
bool ok = false;
auto disAll =
qEnvironmentVariableIntValue("WING_DISABLE_PLUGIN_SYSTEM", &ok);
@ -4603,6 +4656,13 @@ void PluginSystem::destory() {
delete item;
}
_loadeddevs.clear();
if (_manager && _manInfo) {
auto set = std::make_unique<QSettings>(
udir.absoluteFilePath(_manInfo->id), QSettings::Format::IniFormat);
_manager->unload(set);
delete _manager;
}
}
EditorView *PluginSystem::pluginCurrentEditor(IWingPlugin *plg) const {

View File

@ -103,18 +103,9 @@ private:
QExplicitlySharedDataPointer<UniqueIdGenerator::UniqueId>;
public:
struct PluginInfo {
QString id;
QVersionNumber version;
QString vendor;
QList<WingDependency> dependencies;
QString author;
QString license;
QString url;
};
enum class PluginStatus {
Valid,
SDKVersion,
BrokenVersion,
InvalidID,
DupID,
@ -257,13 +248,19 @@ private:
void registerMarcoDevice(IWingDevice *plg);
private:
void registerRibbonTools(const QList<WingRibbonToolBoxInfo> &tools);
void registeredSettingPages(const QVariant &itptr,
const QList<SettingPage *> &pages);
void registerPluginDockWidgets(IWingPluginBase *p);
void registerPluginPages(IWingPluginBase *p);
public:
// fpr crash checking
QString currentLoadingPlugin() const;
IWingManager *monitorManager() const;
const std::optional<PluginInfo> &monitorManagerInfo() const;
private:
template <typename T>
T readBasicTypeContent(IWingPlugin *plg, qsizetype offset) {

View File

@ -59,18 +59,35 @@ SkinManager &SkinManager::instance() {
return instance;
}
void SkinManager::setTheme(SkinManager::Theme theme) { m_theme = theme; }
void SkinManager::setTheme(SkinManager::Theme theme) {
if (m_theme != theme) {
m_theme = theme;
m_cache.clear();
}
}
QIcon SkinManager::themeIcon(const QString &name) {
switch (m_theme) {
case Theme::Dark:
return QIcon(QStringLiteral("://dark/") + name +
QStringLiteral(".svg"));
case Theme::Light:
return QIcon(QStringLiteral("://light/") + name +
QStringLiteral(".svg"));
auto picon = m_cache.find(name);
if (picon == m_cache.end()) {
switch (m_theme) {
case Theme::Dark: {
QIcon icon(QStringLiteral("://dark/") + name +
QStringLiteral(".svg"));
m_cache.insert(name, icon);
return icon;
}
case Theme::Light: {
QIcon icon(QStringLiteral("://light/") + name +
QStringLiteral(".svg"));
m_cache.insert(name, icon);
return icon;
}
default:
return {};
}
} else {
return *picon;
}
return {};
}
SkinManager::Theme SkinManager::currentTheme() const { return m_theme; }

View File

@ -48,6 +48,8 @@ private:
private:
Theme m_theme;
QHash<QString, QIcon> m_cache;
explicit SkinManager();
Q_DISABLE_COPY_MOVE(SkinManager)

View File

@ -44,8 +44,6 @@ WingAngelAPI::WingAngelAPI() {
WingAngelAPI::~WingAngelAPI() {}
int WingAngelAPI::sdkVersion() const { return WingHex::SDKVERSION; }
bool WingAngelAPI::init(const std::unique_ptr<QSettings> &set) {
Q_UNUSED(set);
return true;

View File

@ -39,7 +39,6 @@ public:
// IWingPlugin interface
public:
virtual int sdkVersion() const override;
virtual bool init(const std::unique_ptr<QSettings> &set) override;
virtual void unload(std::unique_ptr<QSettings> &set) override;
virtual const QString pluginName() const override;

View File

@ -178,8 +178,6 @@ WingCStruct::WingCStruct() : WingHex::IWingPlugin() {
WingCStruct::~WingCStruct() {}
int WingCStruct::sdkVersion() const { return WingHex::SDKVERSION; }
bool WingCStruct::init(const std::unique_ptr<QSettings> &set) {
Q_UNUSED(set);
resetEnv();
@ -211,8 +209,7 @@ WingCStruct::RegisteredEvents WingCStruct::registeredEvents() const {
return evs;
}
QHash<WingHex::SettingPage *, bool>
WingCStruct::registeredSettingPages() const {
QList<WingHex::SettingPage *> WingCStruct::registeredSettingPages() const {
return _setpgs;
}

View File

@ -35,7 +35,6 @@ public:
// IWingPluginBase interface
public:
virtual int sdkVersion() const override;
virtual bool init(const std::unique_ptr<QSettings> &set) override;
virtual void unload(std::unique_ptr<QSettings> &set) override;
virtual const QString pluginName() const override;
@ -47,7 +46,7 @@ public:
// IWingPlugin interface
public:
virtual RegisteredEvents registeredEvents() const override;
virtual QHash<WingHex::SettingPage *, bool>
virtual QList<WingHex::SettingPage *>
registeredSettingPages() const override;
virtual QHash<QString, ScriptFnInfo> registeredScriptFns() const override;
virtual bool eventOnScriptPragma(const QString &script,
@ -118,7 +117,7 @@ private:
private:
CTypeParser _parser;
QHash<WingHex::SettingPage *, bool> _setpgs;
QList<WingHex::SettingPage *> _setpgs;
QHash<QString, WingCStruct::ScriptFnInfo> _scriptInfo;
QHash<QString, WingHex::IWingPlugin::UNSAFE_SCFNPTR> _scriptUnsafe;
};

View File

@ -1637,7 +1637,6 @@ void MainWindow::buildUpSettingDialog() {
auto plgPage = new PluginSettingDialog(m_setdialog);
connect(plgPage, &SettingPage::optionNeedRestartChanged, m_setdialog,
&SettingDialog::toastTakeEffectReboot);
plgPage->buildUp(m_plgPages);
m_setdialog->addPage(plgPage);
id = plgPage->id();
Q_ASSERT(!id.isEmpty());
@ -1662,9 +1661,7 @@ void MainWindow::buildUpSettingDialog() {
usedIDs.append(id);
qApp->processEvents();
for (auto page_p = m_settingPages.constKeyValueBegin();
page_p != m_settingPages.constKeyValueEnd(); ++page_p) {
auto page = page_p->first;
for (auto &page : m_settingPages) {
auto name = page->name();
auto id = page->id();
@ -1690,7 +1687,7 @@ void MainWindow::buildUpSettingDialog() {
connect(page, &SettingPage::optionNeedRestartChanged, m_setdialog,
&SettingDialog::toastTakeEffectReboot);
m_setdialog->addPage(page);
if (page_p->second) {
if (page->showInRibbon()) {
auto icon = page->categoryIcon();
addPannelAction(m_pluginSettingsGroup, icon, name,
[=] { m_setdialog->showConfig(id); });

View File

@ -564,8 +564,7 @@ private:
QList<QMenu *> m_hexContextMenu;
QHash<IWingPlugin *, QList<QSharedPointer<WingEditorViewWidget::Creator>>>
m_editorViewWidgets;
QHash<SettingPage *, bool> m_settingPages;
QList<PluginPage *> m_plgPages;
QList<SettingPage *> m_settingPages;
// these variables will be invalid after restoring state
ads::CDockAreaWidget *m_leftViewArea = nullptr;

View File

@ -18,7 +18,6 @@
#include "pluginsettingdialog.h"
#include "class/pluginsystem.h"
#include "class/settingmanager.h"
#include "dbghelper.h"
#include "ui_pluginsettingdialog.h"
#include "utilities.h"
@ -48,6 +47,7 @@ PluginSettingDialog::PluginSettingDialog(QWidget *parent)
auto &plgsys = PluginSystem::instance();
auto pico = ICONRES("plugin");
ui->plglist->clear();
for (auto &p : plgsys.plugins()) {
auto pco = p->pluginIcon();
ui->plglist->addItem(
@ -63,17 +63,32 @@ PluginSettingDialog::PluginSettingDialog(QWidget *parent)
new QListWidgetItem(pco.isNull() ? pico : pco, d->pluginName()));
}
ui->txtd->clear();
auto minfo = plgsys.monitorManagerInfo();
if (minfo) {
auto sep = QStringLiteral(" : ");
ui->txtm->append(getWrappedText(tr("ID") + sep + minfo->id));
ui->txtm->append(getWrappedText(tr("License") + sep + minfo->license));
ui->txtm->append(getWrappedText(tr("Author") + sep + minfo->author));
ui->txtm->append(getWrappedText(tr("Vendor") + sep + minfo->vendor));
ui->txtm->append(
getWrappedText(tr("Version") + sep + minfo->version.toString()));
ui->txtm->append(getWrappedText(
tr("URL") + sep + QStringLiteral("<a href=\"") + minfo->url +
QStringLiteral("\">") + minfo->url + QStringLiteral("</a>")));
ui->txtm->append(getWrappedText(tr("Comment") + sep));
auto p = plgsys.monitorManager();
if (p) {
ui->txtm->append(getWrappedText(p->comment()));
}
} else {
ui->txtm->setText(tr("NoMonitorPlugin"));
}
}
PluginSettingDialog::~PluginSettingDialog() { delete ui; }
void PluginSettingDialog::buildUp(const QList<PluginPage *> &pages) {
ASSERT_SINGLETON;
for (auto &page : pages) {
ui->tabWidget->addTab(page, page->categoryIcon(), page->name());
}
}
void PluginSettingDialog::reload() {
this->blockSignals(true);
auto &set = SettingManager::instance();
@ -112,17 +127,18 @@ void PluginSettingDialog::on_devlist_currentRowChanged(int currentRow) {
auto info = plgsys.getPluginInfo(plg);
ui->txtd->clear();
ui->txtd->append(getWrappedText(tr("ID") + " : " + info.id));
ui->txtd->append(getWrappedText(tr("Name") + " : " + plg->pluginName()));
ui->txtd->append(getWrappedText(tr("License") + " : " + info.license));
ui->txtd->append(getWrappedText(tr("Author") + " : " + info.author));
ui->txtd->append(getWrappedText(tr("Vendor") + " : " + info.vendor));
static auto sep = QStringLiteral(" : ");
ui->txtd->append(getWrappedText(tr("ID") + sep + info.id));
ui->txtd->append(getWrappedText(tr("Name") + sep + plg->pluginName()));
ui->txtd->append(getWrappedText(tr("License") + sep + info.license));
ui->txtd->append(getWrappedText(tr("Author") + sep + info.author));
ui->txtd->append(getWrappedText(tr("Vendor") + sep + info.vendor));
ui->txtd->append(
getWrappedText(tr("Version") + " : " + info.version.toString()));
getWrappedText(tr("Version") + sep + info.version.toString()));
ui->txtd->append(
getWrappedText(tr("Comment") + " : " + plg->pluginComment()));
getWrappedText(tr("Comment") + sep + plg->pluginComment()));
ui->txtd->append(getWrappedText(
tr("URL") + " : " + QStringLiteral("<a href=\"") + info.url +
tr("URL") + sep + QStringLiteral("<a href=\"") + info.url +
QStringLiteral("\">") + info.url + QStringLiteral("</a>")));
}
@ -136,16 +152,16 @@ void PluginSettingDialog::on_plglist_currentRowChanged(int currentRow) {
auto info = plgsys.getPluginInfo(plg);
ui->txtc->clear();
ui->txtc->append(getWrappedText(tr("ID") + " : " + info.id));
ui->txtc->append(getWrappedText(tr("Name") + " : " + plg->pluginName()));
ui->txtc->append(getWrappedText(tr("License") + " : " + info.license));
ui->txtc->append(getWrappedText(tr("Author") + " : " + info.author));
ui->txtc->append(getWrappedText(tr("Vendor") + " : " + info.vendor));
static auto sep = QStringLiteral(" : ");
ui->txtc->append(getWrappedText(tr("ID") + sep + info.id));
ui->txtc->append(getWrappedText(tr("Name") + sep + plg->pluginName()));
ui->txtc->append(getWrappedText(tr("License") + sep + info.license));
ui->txtc->append(getWrappedText(tr("Author") + sep + info.author));
ui->txtc->append(getWrappedText(tr("Vendor") + sep + info.vendor));
ui->txtc->append(
getWrappedText(tr("Version") + " : " + info.version.toString()));
getWrappedText(tr("Version") + sep + info.version.toString()));
ui->txtc->append(
getWrappedText(tr("Comment") + " : " + plg->pluginComment()));
getWrappedText(tr("Comment") + sep + plg->pluginComment()));
if (!info.dependencies.isEmpty()) {
ui->txtc->append(getWrappedText(tr("pluginDependencies:")));
for (auto &d : info.dependencies) {
@ -156,7 +172,7 @@ void PluginSettingDialog::on_plglist_currentRowChanged(int currentRow) {
}
}
ui->txtc->append(getWrappedText(
tr("URL") + " : " + QStringLiteral("<a href=\"") + info.url +
tr("URL") + sep + QStringLiteral("<a href=\"") + info.url +
QStringLiteral("\">") + info.url + QStringLiteral("</a> ")));
}

View File

@ -32,8 +32,6 @@ public:
explicit PluginSettingDialog(QWidget *parent = nullptr);
~PluginSettingDialog();
void buildUp(const QList<WingHex::PluginPage *> &pages);
private:
Ui::PluginSettingDialog *ui;

View File

@ -167,6 +167,24 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="icon">
<iconset resource="../../resources.qrc">
<normaloff>:/com.wingsummer.winghex/images/monitor.png</normaloff>:/com.wingsummer.winghex/images/monitor.png</iconset>
</attribute>
<attribute name="title">
<string>APIMonitor</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QTextBrowser" name="txtm">
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>

View File

@ -57,7 +57,15 @@ Q_DECL_UNUSED static inline QString NAMEICONRES(const QString &name) {
}
Q_DECL_UNUSED static inline QIcon ICONRES(const QString &name) {
return QIcon(NAMEICONRES(name));
static QHash<QString, QIcon> cache;
auto picon = cache.find(name);
if (picon == cache.end()) {
QIcon icon(NAMEICONRES(name));
cache.insert(name, icon);
return icon;
} else {
return *picon;
}
}
class Utilities {