diff --git a/3rdparty/QHexView/qhexview.h b/3rdparty/QHexView/qhexview.h
index d9fe8d2..0f23e70 100644
--- a/3rdparty/QHexView/qhexview.h
+++ b/3rdparty/QHexView/qhexview.h
@@ -128,7 +128,7 @@ private:
signals:
void documentChanged(QHexDocument *doc);
void cursorLocationChanged();
- void cursorSelectionChanged(); // TODO
+ void cursorSelectionChanged();
void canUndoChanged(bool canUndo);
void canRedoChanged(bool canRedo);
void documentSaved(bool saved);
diff --git a/TestPlugin/lang/TestPlugin_zh_CN.ts b/TestPlugin/lang/TestPlugin_zh_CN.ts
index b7f974f..ea3cb8a 100644
--- a/TestPlugin/lang/TestPlugin_zh_CN.ts
+++ b/TestPlugin/lang/TestPlugin_zh_CN.ts
@@ -287,28 +287,28 @@
数据可视化
-
-
+
+
UpdateTextTreeError
更新文本树失败
-
+
UpdateTextListByModelError
通过模型更新文本列表失败
-
+
UpdateTextTableByModelError
通过模型更新文本表格失败
-
+
UpdateTextTreeByModelError
通过模型更新文本树失败
-
+
Choose
选择
diff --git a/TestPlugin/testform.cpp b/TestPlugin/testform.cpp
index ba2e81f..71866f2 100644
--- a/TestPlugin/testform.cpp
+++ b/TestPlugin/testform.cpp
@@ -329,16 +329,19 @@ void TestForm::on_btnGetColor_clicked() {
}
void TestForm::on_btnText_2_clicked() {
- emit _plg->visual.updateText(ui->teDataVisual->toPlainText());
+ emit _plg->visual.updateText(ui->teDataVisual->toPlainText(),
+ QStringLiteral("TestForm"));
}
void TestForm::on_btnTextList_clicked() {
auto txts = ui->teDataVisual->toPlainText().split('\n');
- emit _plg->visual.updateTextList(txts, _click, _dblclick);
+ emit _plg->visual.updateTextList(txts, QStringLiteral("TestForm"), _click,
+ _dblclick);
}
void TestForm::on_btnTextTree_clicked() {
auto ret = emit _plg->visual.updateTextTree(ui->teDataVisual->toPlainText(),
+ QStringLiteral("TestForm"),
_click, _dblclick);
if (!ret) {
emit _plg->msgbox.critical(this, QStringLiteral("Test"),
@@ -349,7 +352,8 @@ void TestForm::on_btnTextTree_clicked() {
void TestForm::on_btnTextTable_clicked() {
auto ret = emit _plg->visual.updateTextTable(
ui->teDataVisual->toPlainText(),
- {WingHex::WINGSUMMER, WingHex::WINGSUMMER}, {}, _click, _dblclick);
+ {WingHex::WINGSUMMER, WingHex::WINGSUMMER}, {},
+ QStringLiteral("TestForm"), _click, _dblclick);
if (!ret) {
emit _plg->msgbox.critical(this, QStringLiteral("Test"),
tr("UpdateTextTreeError"));
@@ -363,8 +367,8 @@ void TestForm::on_btnTextListByModel_clicked() {
buffer.append(WingHex::WINGSUMMER % QString::number(i));
}
model->setStringList(buffer);
- auto ret =
- emit _plg->visual.updateTextListByModel(model, _click, _dblclick);
+ auto ret = emit _plg->visual.updateTextListByModel(
+ model, QStringLiteral("TestForm"), _click, _dblclick);
if (!ret) {
emit _plg->msgbox.critical(this, QStringLiteral("Test"),
tr("UpdateTextListByModelError"));
@@ -373,8 +377,8 @@ void TestForm::on_btnTextListByModel_clicked() {
void TestForm::on_btnTextTableByModel_clicked() {
auto model = new TestTableModel;
- auto ret =
- emit _plg->visual.updateTextTableByModel(model, _click, _dblclick);
+ auto ret = emit _plg->visual.updateTextTableByModel(
+ model, QStringLiteral("TestForm"), _click, _dblclick);
if (!ret) {
emit _plg->msgbox.critical(this, QStringLiteral("Test"),
tr("UpdateTextTableByModelError"));
@@ -384,8 +388,8 @@ void TestForm::on_btnTextTableByModel_clicked() {
void TestForm::on_btnTextTreeByModel_clicked() {
auto model = new QFileSystemModel;
model->setRootPath(QDir::currentPath());
- auto ret =
- emit _plg->visual.updateTextTreeByModel(model, _click, _dblclick);
+ auto ret = emit _plg->visual.updateTextTreeByModel(
+ model, QStringLiteral("TestForm"), _click, _dblclick);
if (!ret) {
emit _plg->msgbox.critical(this, QStringLiteral("Test"),
tr("UpdateTextTreeByModelError"));
diff --git a/lang/zh_CN/winghex.ts b/lang/zh_CN/winghex.ts
index 2891a81..d6a146c 100644
--- a/lang/zh_CN/winghex.ts
+++ b/lang/zh_CN/winghex.ts
@@ -442,7 +442,7 @@
编码
-
+
Untitled
未命名
@@ -589,29 +589,29 @@
FindResultModel
-
+
line
行
-
+
col
列
-
+
offset
偏移
-
+
value
值
-
+
encoding
-
+ 解码
@@ -851,978 +851,982 @@
MainWindow
-
+
File
文件
-
-
+
+
View
视图
-
+
About
关于
-
+
WingHexExplorer
羽云十六进制编辑器
-
+
loc:
坐标:
-
+
sel:
选长:
-
+
Edit
编辑
-
+
Script
脚本
-
-
-
+
+
+
Plugin
插件
-
+
Setting
设置
-
-
+
+
Log
日志
-
+
ExportFindResult
导出搜索结果
-
+
ClearFindResult
清空记录
-
+
FindResult
搜索结果
-
-
-
+
+
+
Copy
复制
-
-
-
-
+
+
+
+
CopyToClipBoard
数据已拷贝到粘贴板
-
+
LittleEndian
小端
-
+
BigEndian
大端
-
+
Number
数值
-
-
+
+
CheckSum
校验和
-
-
+
+
DeleteBookMark
删除书签
-
-
+
+
ClearBookMark
清空书签
-
-
-
-
+
+
+
+
BookMark
书签
-
+
DecodeText
解码字符串
-
+
ScriptConsole
脚本控制台
-
+
+
DVList
可视化列表
-
+
+
DVTree
可视化树数据
-
+
+
DVTable
可视化表格
-
+
+
DVText
可视化文本
-
-
+
+
Basic
基础
-
+
New
新建
-
+
OpenF
打开文件
-
+
OpenFR
打开局部文件
-
+
OpenWorkSpace
打开工作区
-
+
OpenD
打开驱动器
-
+
RecentFiles
最近打开
-
+
Reload
重新加载
-
-
+
+
Save
保存
-
+
SaveAs
另存为
-
+
Export
导出
-
+
SaveSel
保存选区字节
-
-
-
-
+
+
+
+
General
基本
-
+
Undo
撤销
-
+
Redo
恢复
-
+
Cut
剪切
-
+
Paste
粘贴
-
+
Delete
删除
-
+
Clone
克隆
-
+
Lookup
查询
-
+
Find
查找
-
+
Goto
跳转
-
+
Encoding
编码
-
+
FileInfo
文件信息
-
-
+
+
Hex
十六进制
-
+
CutHex
剪切(十六进制)
-
+
CopyHex
复制(十六进制)
-
+
PasteHex
粘贴(十六进制)
-
-
+
+
Fill
填充
-
+
FillZero
填充零
-
-
-
-
-
+
+
+
+
+
MetaData
标注
-
+
DeleteMetadata
删除标注
-
+
ClearMetadata
清空标注
-
+
MetaDataEdit
编辑标注
-
+
DeleteMetaData
删除标注
-
+
ClearMetaData
清空标注
-
+
Display
显示
-
+
ViewText
文本预览
-
+
Scale
缩放
-
+
SetupRecent
启动最近文件服务
-
+
SetupUI
初始化界面
-
+
SetupDocking
启动 Dock 服务
-
+
LaunchingLog
启动日志系统
-
+
SetupPluginSystem
启动插件系统
-
+
LoadingPlg:
加载插件中:
-
+
SetupConsole
启动脚本控制台
-
+
SetupScriptManager
启动脚本管理器
-
+
SetupScriptService
启动脚本服务
-
+
SetupScriptEditor
构建脚本编辑器
-
+
SetupSetDialog
构建设置窗体
-
+
SetupPlgWidgets
启动插件组件
-
+
SetupDockingLayout
恢复 Dock 布局
-
+
SetupWaiting
启动即将完成
-
+
SetupFinished
启动完毕
-
+
ResetScale
重置缩放
-
+
ShowMetafg
标注前景色
-
+
ShowMetabg
标注背景色
-
+
ShowMetaComment
批注
-
+
MetaShowAll
显示所有标注
-
+
MetaHideAll
隐藏所有标注
-
+
FileStatus
文件状态
-
+
InfoSave
是否保存
-
+
ReadOnly
可读写
-
+
SetLocked
启用/禁用锁定编辑
-
+
ErrUnLock
锁定编辑失败
-
+
SetOver
启用/禁用改变大小
-
+
ErrUnOver
锁定文件大小失败
-
+
InfoCanOverLimit
当前编辑处于受限模式!
-
+
Window
窗体
-
+
Editor
编辑器
-
+
Tools
工具
-
+
HexEditorLayout
编辑器布局
-
+
SetBaseAddr
设置基址
-
+
addressBase
基址
-
+
inputAddressBase
请输入基址
-
+
WarnBigBaseAddress
基址过大,你得到的地址将会不正确!
-
+
ErrBaseAddress
非法基址输入
-
+
SetColInfo
显示/隐藏地址栏
-
+
SetHeaderInfo
显示/隐藏表头
-
+
SetAsciiString
显示/隐藏解码字符串
-
+
Layout
布局
-
+
Fullscreen
全屏
-
+
Default
默认
-
+
RestoreLayout
恢复布局
-
-
+
+
SaveLayout
保存布局
-
+
ExportLog
导出日志
-
+
ClearLog
清空日志
-
+
ScriptEditor
脚本编辑器
-
+
Scripts
脚本仓库
-
+
PluginFunctions
插件功能
-
+
ScriptSetting
脚本设置
-
+
PluginSettings
插件设置
-
+
Info
信息
-
+
Software
软件
-
+
Sponsor
赞助
-
+
CheckUpdate
检查更新
-
+
Wiki
网页 Wiki
-
+
AboutQT
关于 QT
-
+
SetPageIDEmptyTryUseName
设置页 ID 为空,尝试使用名称作为 ID
-
+
SetPageDupNameIgnored
设置页重复的 ID 名称,已忽略加载
-
+
Plugin %1 contains a duplicate ID (%2) that is already registered by plugin %3
插件 %1 包含重复 ID (%2),该 ID 已被插件 %3 注册
-
-
+
+
ChooseFile
选择文件
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Error
错误
-
-
-
-
+
+
+
+
FileNotExist
文件不存在!
-
-
-
-
-
+
+
+
+
+
FilePermission
因文件权限无法继续!
-
+
ProjectFile (*.wingpro)
项目文件 (*.wingpro)
-
+
Root Required!
需要管理员权限继续操作!
-
+
ReloadSuccessfully
文件重新加载成功!
-
+
ReloadUnSuccessfully
文件重新加载失败!
-
-
-
+
+
+
ChooseSaveFile
请选择保存文件路径:
-
+
NoMoreClone
克隆已到上限,无法继续操作!
-
+
FindFininishBusy
查找任务繁忙,请勿重复查找!
-
+
MayTooMuchFindResult
搜索数量已到达上限,结果可能不全,建议请按区段搜索。
-
+
SaveLayoutSuccess
保存布局成功
-
+
SaveLayoutError
保存布局失败
-
+
ConfirmSave
正在关闭未保存的文件或工作区,你确定保存吗?
-
+
ConfirmAPPSave
你尝试关闭程序,但仍存在未保存的文件或工作区,你确定保存这些更改吗?
-
-
+
+
SaveSuccessfully
保存成功!
-
-
+
+
SaveWSError
保存工作区错误!
-
-
-
+
+
+
Warn
警告
-
+
ScriptObjShow
脚本对象
-
-
-
+
+
+
SourceChanged
局部打开原始文件更改!
-
-
+
+
SaveSourceFileError
由于原文件更改,保存文件失败!
-
+
SaveUnSuccessfully
保存失败!
-
+
ChooseExportFile
请选择导出文件路径:
-
+
ExportSuccessfully
导出成功!
-
+
ExportSourceFileError
由于原文件更改,导出文件失败!
-
+
ExportUnSuccessfully
导出失败!
-
+
SaveSelSuccess
保存选区字节成功!
-
+
SaveSelError
保存选区字节失败,因文件不具有可写权限!
-
-
+
+
CutToClipBoard
数据已剪切到粘贴板!
-
-
+
+
UnCutToClipBoard
由于保持大小限制,数据剪切到粘贴板失败!
-
-
+
+
UnCopyToClipBoard
由于保持大小限制,数据剪切到复制板失败!
-
+
FindFininish
查找结果完毕!
-
+
PleaseInputFill
请输入填充字节值
-
+
FillInputError
填充字节输入错误
-
-
+
+
InputComment
请输入批注:
-
-
+
+
NoSelection
没有选区,无法继续的操作!
-
+
NoMetaData
无可编辑标记
-
+
EmptyFindResult
没有可导出的搜索结果!
-
+
SaveFindResult
导出搜索结果成功!
-
+
SaveFindResultError
导出结果失败!
-
+
TooManyBytesDecode
超出解码字节限制……
-
+
ExportLogError
导出日志失败!
-
+
ExportLogSuccess
导出日志成功,路径:
-
+
ClearLogSuccess
清空日志成功!
-
+
BadNetwork
无法与远程服务器的更新检查建立连接,请检查网络。
-
+
NewestVersion
当前软件为最新版本
-
-
+
+
OlderVersion
你使用的软件为老版本,建议到 Github 和 Gitee 的仓库发行版下载更新。
-
+
CheckingUpdate
检查更新中……
-
+
Too much opened files
打开的文件过多,无法继续操作!
-
+
CopyLimit
拷贝字节超出限制
-
+
ErrOpenFileBelow
打开文件出现错误(由于权限不足),如下为打开错误的文件:
@@ -2033,92 +2037,127 @@
PluginSystem
-
+
LoadingPlugin
正在加载插件:
-
+
RegisteredFnDup
注册重复函数对象
-
+
ErrLoadPluginSign
插件加载失败:非法插件签名!
-
+
ErrLoadPluginSDKVersion
插件加载失败:非法插件 SDK 版本!
-
+
ErrLoadPluginNoName
插件加载失败:非法插件名称!
-
+
+ ErrLoadInvalidPUID
+ 插件加载失败:非法插件唯一标志符!
+
+
+
ErrLoadLoadedPlugin
插件加载失败:重复加载插件!
-
+
ErrLoadInitPlugin
插件加载失败:初始化插件失败!
-
+
PluginName :
插件名:
-
+
PluginAuthor :
插件作者:
-
+
PluginWidgetRegister
注册插件对象中……
-
+
EmptyNameDockWidget:
空的贴边组件名:
-
+
InvalidNameDockWidget:
无效贴边组件名:
-
+
InvalidNullDockWidget:
无效空贴边组件:
-
+
[EvilCall]
【恶意调用】
-
+
Not allowed operation in non-UI thread
该操作在非 UI 线程非法
-
+
UnsafePluginDir
不安全的插件目录,请将插件目录设置为仅管理员账户可写
-
+
FoundPluginCount
总计发现插件数目:
-
+
+ PluginLoadingFailedSummary
+ 有依赖插件加载失败总结
+
+
+
+ - PluginName:
+ - 插件名:
+
+
+
+ - Dependencies:
+ - 依赖:
+
+
+
+ PUID:
+ 插件唯一标志符:
+
+
+
+ Version:
+ 版本:
+
+
+
+ MD5:
+ MD5 校验和:
+
+
+
PluginLoadingFinished
加载插件完毕!
@@ -2159,8 +2198,8 @@
QApplication
-
-
+
+
OptionNeedRestart
该设置需要程序重启后生效
@@ -4840,88 +4879,88 @@ Do you wish to keep up to date by reloading the file?
栈跟踪
-
+
Symbol
符号
-
-
-
-
-
-
+
+
+
+
+
+
Error
错误
-
+
Too much opened files
打开的文件过多,无法继续操作!
-
+
ConfirmSave
正在关闭未保存的脚本文件,你确定保存吗?
-
+
ScriptSaveFailedClose
脚本保存失败,你仍确认关闭吗?
-
-
+
+
ChooseFile
选择文件
-
-
-
+
+
+
FilePermission
因文件权限无法继续!
-
+
ReloadSuccessfully
文件重新加载成功!
-
+
ReloadUnSuccessfully
文件重新加载失败!
-
+
ChooseSaveFile
请选择保存文件路径:
-
-
+
+
SaveSuccessfully
保存成功!
-
+
SaveUnSuccessfully
保存失败!
-
+
FormatCodeFailed
代码格式化失败
-
-
+
+
CannotSave2RunScript
无法保存,故无法继续运行脚本。
-
-
+
+
ScriptStillRunning
脚本仍在运行,你确定要退出吗?
@@ -5133,12 +5172,22 @@ Do you wish to keep up to date by reloading the file?
为 AngelScript 脚本提供调用主机 API 能力的内部插件。
-
+
RegisterScriptFnInvalidSig:
因脚本函数签名非法而注册失败:
-
+
+ InvalidEnumName:
+ 非法枚举名:
+
+
+
+ InvalidEnumValue:
+ 非法枚举值:
+
+
+
NotSupportedQMetaType:
不支持的 QT 数据元类型:
diff --git a/src/class/ascompletion.cpp b/src/class/ascompletion.cpp
index 573a337..eae1cff 100644
--- a/src/class/ascompletion.cpp
+++ b/src/class/ascompletion.cpp
@@ -186,7 +186,7 @@ void AsCompletion::complete(const QDocumentCursor &c, const QString &trigger) {
return;
}
} else if (rbegin->content == DOT_TRIGGER) {
- // TODO
+ // TODO only PR
} else {
applyEmptyNsNode(nodes);
}
diff --git a/src/class/richtextitemdelegate.cpp b/src/class/richtextitemdelegate.cpp
index e2e707a..34ab0e3 100644
--- a/src/class/richtextitemdelegate.cpp
+++ b/src/class/richtextitemdelegate.cpp
@@ -1,3 +1,20 @@
+/*==============================================================================
+** Copyright (C) 2024-2027 WingSummer
+**
+** This program is free software: you can redistribute it and/or modify it under
+** the terms of the GNU Affero General Public License as published by the Free
+** Software Foundation, version 3.
+**
+** This program is distributed in the hope that it will be useful, but WITHOUT
+** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+** FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+** details.
+**
+** You should have received a copy of the GNU Affero General Public License
+** along with this program. If not, see .
+** =============================================================================
+*/
+
#include "richtextitemdelegate.h"
#include
@@ -11,44 +28,64 @@ RichTextItemDelegate::RichTextItemDelegate(QObject *parent)
void RichTextItemDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const {
- auto options = option;
- initStyleOption(&options, index);
+ if (!index.isValid())
+ return;
- painter->save();
+ // Get the rich text content
+ QString text = index.data(Qt::DisplayRole).toString();
+ if (text.isEmpty())
+ return;
+ // Get alignment
+ QVariant alignmentVariant = index.data(Qt::TextAlignmentRole);
+ Qt::Alignment alignment = alignmentVariant.isValid()
+ ? Qt::Alignment(alignmentVariant.toInt())
+ : Qt::AlignLeft;
+
+ // Set up a QTextDocument to render the HTML content
QTextDocument doc;
- doc.setHtml(options.text);
+ doc.setHtml(text);
- options.text.clear();
- options.widget->style()->drawControl(QStyle::CE_ItemViewItem, &options,
- painter);
+ // Disable word wrapping
+ QTextOption textOption;
+ textOption.setWrapMode(QTextOption::NoWrap);
+ doc.setDefaultTextOption(textOption);
- // shift text right to make icon visible
- QSize iconSize = options.icon.actualSize(options.rect.size());
- painter->translate(options.rect.left() + iconSize.width(),
- options.rect.top());
- QRect clip(0, 0, options.rect.width() + iconSize.width(),
- options.rect.height());
+ // Clip the painter to the cell rectangle
+ painter->save();
+ painter->setClipRect(option.rect);
- painter->setClipRect(clip);
- QAbstractTextDocumentLayout::PaintContext ctx;
- // set text color to red for selected item
- if (option.state & QStyle::State_Selected)
- ctx.palette.setColor(QPalette::Text, Qt::red);
+ // Calculate the rendering rectangle based on alignment
+ QRect rect = option.rect;
+ QSize contentSize = doc.size().toSize();
+ if (alignment & Qt::AlignHCenter) {
+ rect.setLeft(rect.left() + (rect.width() - contentSize.width()) / 2);
+ } else if (alignment & Qt::AlignRight) {
+ rect.setLeft(rect.right() - contentSize.width());
+ }
- ctx.clip = clip;
- doc.documentLayout()->draw(painter, ctx);
+ if (alignment & Qt::AlignVCenter) {
+ rect.setTop(rect.top() + (rect.height() - contentSize.height()) / 2);
+ } else if (alignment & Qt::AlignBottom) {
+ rect.setTop(rect.bottom() - contentSize.height());
+ }
+
+ // Render the document in the adjusted rectangle
+ painter->translate(rect.topLeft());
+ doc.setTextWidth(option.rect.width());
+ doc.drawContents(painter);
painter->restore();
}
QSize RichTextItemDelegate::sizeHint(const QStyleOptionViewItem &option,
const QModelIndex &index) const {
- auto options = option;
- initStyleOption(&options, index);
+ QString text = index.data(Qt::DisplayRole).toString();
+ if (text.isEmpty())
+ return QStyledItemDelegate::sizeHint(option, index);
QTextDocument doc;
- doc.setHtml(options.text);
- doc.setTextWidth(options.rect.width());
- return QSize(doc.idealWidth(), doc.size().height());
+ doc.setHtml(text);
+ doc.setTextWidth(option.rect.width());
+ return doc.size().toSize();
}
diff --git a/src/class/richtextitemdelegate.h b/src/class/richtextitemdelegate.h
index 571fb4c..3be18ae 100644
--- a/src/class/richtextitemdelegate.h
+++ b/src/class/richtextitemdelegate.h
@@ -1,3 +1,20 @@
+/*==============================================================================
+** Copyright (C) 2024-2027 WingSummer
+**
+** This program is free software: you can redistribute it and/or modify it under
+** the terms of the GNU Affero General Public License as published by the Free
+** Software Foundation, version 3.
+**
+** This program is distributed in the hope that it will be useful, but WITHOUT
+** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+** FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+** details.
+**
+** You should have received a copy of the GNU Affero General Public License
+** along with this program. If not, see .
+** =============================================================================
+*/
+
#ifndef RICHTEXTITEMDELEGATE_H
#define RICHTEXTITEMDELEGATE_H
diff --git a/src/class/scriptconsolemachine.cpp b/src/class/scriptconsolemachine.cpp
index 09df21a..319ccc1 100644
--- a/src/class/scriptconsolemachine.cpp
+++ b/src/class/scriptconsolemachine.cpp
@@ -186,9 +186,6 @@ bool ScriptConsoleMachine::execString(asIScriptEngine *engine,
info.message = str;
emit onOutput(MessageType::Info, info);
return true;
- } else if (code.startsWith(QStringLiteral("import "))) {
- // TODO
- return true;
} else {
return ExecuteString(engine, code.toUtf8(), mod, immediateContext()) >=
0;
diff --git a/src/class/wingangelapi.cpp b/src/class/wingangelapi.cpp
index b4f6a02..7fbadc9 100644
--- a/src/class/wingangelapi.cpp
+++ b/src/class/wingangelapi.cpp
@@ -80,6 +80,17 @@ const QString WingAngelAPI::pluginComment() const {
"ability to call the host API.");
}
+void WingAngelAPI::registerScriptEnums(
+ const QString &ns, const QHash>> &objs) {
+ Q_ASSERT(!ns.isEmpty());
+ if (objs.isEmpty()) {
+ return;
+ }
+
+ // check it later
+ _objs.insert(ns, objs);
+}
+
void WingAngelAPI::registerScriptFns(const QString &ns,
const QHash &rfns) {
Q_ASSERT(!ns.isEmpty());
@@ -115,6 +126,7 @@ void WingAngelAPI::installAPI(ScriptMachine *machine) {
installDataVisualAPI(engine, stringTypeID);
installScriptFns(engine);
+ installScriptEnums(engine);
}
void WingAngelAPI::installLogAPI(asIScriptEngine *engine) {
@@ -1107,34 +1119,35 @@ void WingAngelAPI::installDataVisualAPI(asIScriptEngine *engine, int stringID) {
auto datavis = &this->visual;
- registerAPI(
+ registerAPI(
engine,
std::bind(&WingHex::WingPlugin::DataVisual::updateText, datavis,
- std::placeholders::_1),
- "bool updateText(string &in data)");
+ std::placeholders::_1, std::placeholders::_2),
+ "bool updateText(string &in data, string &in title=\"\")");
- registerAPI(
+ registerAPI(
engine,
std::bind(&WingAngelAPI::_DataVisual_updateTextList, this, stringID,
- std::placeholders::_1),
- "bool updateTextList(array &in data)");
+ std::placeholders::_1, std::placeholders::_2),
+ "bool updateTextList(array &in data, string &in title=\"\")");
- registerAPI(
+ registerAPI(
engine,
std::bind(&WingHex::WingPlugin::DataVisual::updateTextTree, datavis,
- std::placeholders::_1,
+ std::placeholders::_1, std::placeholders::_2,
WingHex::WingPlugin::DataVisual::ClickedCallBack(),
WingHex::WingPlugin::DataVisual::DoubleClickedCallBack()),
- "bool updateTextTree(string &in json)");
+ "bool updateTextTree(string &in json, string &in title=\"\")");
registerAPI(
+ const CScriptArray &, const QString &)>(
engine,
std::bind(&WingAngelAPI::_DataVisual_updateTextTable, this, stringID,
std::placeholders::_1, std::placeholders::_2,
- std::placeholders::_3),
+ std::placeholders::_3, std::placeholders::_4),
"bool updateTextTable(string &in json, array &in headers, "
- "array &in headerNames = array())");
+ "array &in headerNames = array(), string &in "
+ "title=\"\")");
engine->SetDefaultNamespace("");
}
@@ -1169,6 +1182,40 @@ void WingAngelAPI::installScriptFns(asIScriptEngine *engine) {
}
}
+void WingAngelAPI::installScriptEnums(asIScriptEngine *engine) {
+ for (auto pobjs = _objs.constKeyValueBegin();
+ pobjs != _objs.constKeyValueEnd(); ++pobjs) {
+ auto ns = pobjs->first;
+ int r = engine->SetDefaultNamespace(ns.toUtf8());
+ Q_ASSERT(r >= 0);
+ Q_UNUSED(r);
+
+ auto &pobj = pobjs->second;
+ for (auto p = pobj.constKeyValueBegin(); p != pobj.constKeyValueEnd();
+ p++) {
+ auto en = p->first.toUtf8();
+ r = engine->RegisterEnum(en.data());
+ if (r < 0) {
+ emit warn(tr("InvalidEnumName:") + p->first);
+ continue;
+ }
+
+ for (auto &e : p->second) {
+ auto ev = e.first.toUtf8();
+ r = engine->RegisterEnumValue(en.data(), ev.data(), e.second);
+ if (r < 0) {
+ emit warn(tr("InvalidEnumValue:") % p->first %
+ QStringLiteral("::") % e.first %
+ QStringLiteral(" (") % QString::number(e.second) %
+ QStringLiteral(")"));
+ continue;
+ }
+ }
+ }
+ engine->SetDefaultNamespace("");
+ }
+}
+
QStringList WingAngelAPI::cArray2QStringList(const CScriptArray &array,
int stringID, bool *ok) {
bool b = array.GetElementTypeId() == stringID;
@@ -1653,7 +1700,8 @@ void WingAngelAPI::script_call(asIScriptGeneric *gen) {
std::bind(op, gen, std::placeholders::_1, std::placeholders::_2));
}
-bool WingAngelAPI::execScriptCode(const QString &code) {
+bool WingAngelAPI::execScriptCode(const WingHex::SenderInfo &sender,
+ const QString &code) {
if (code.isEmpty()) {
return true;
}
@@ -1666,9 +1714,7 @@ bool WingAngelAPI::execScriptCode(const QString &code) {
}
_console->setMode(ScriptingConsole::Output);
- _console->write(QStringLiteral("(") %
- property("__LAST_CALLER__").toString() %
- QStringLiteral(") "));
+ _console->write(getSenderHeader(sender));
_console->machine()->executeScript(f.fileName());
_console->appendCommandPrompt();
_console->setMode(ScriptingConsole::Input);
@@ -1677,28 +1723,31 @@ bool WingAngelAPI::execScriptCode(const QString &code) {
return false;
}
-bool WingAngelAPI::execScript(const QString &fileName) {
+bool WingAngelAPI::execScript(const WingHex::SenderInfo &sender,
+ const QString &fileName) {
_console->setMode(ScriptingConsole::Output);
- _console->write(QStringLiteral("(") %
- property("__LAST_CALLER__").toString() %
- QStringLiteral(") "));
+ _console->write(getSenderHeader(sender));
auto ret = _console->machine()->executeScript(fileName);
_console->appendCommandPrompt();
_console->setMode(ScriptingConsole::Input);
return ret;
}
-bool WingAngelAPI::execCode(const QString &code) {
+bool WingAngelAPI::execCode(const WingHex::SenderInfo &sender,
+ const QString &code) {
_console->setMode(ScriptingConsole::Output);
- _console->write(QStringLiteral("(") %
- property("__LAST_CALLER__").toString() %
- QStringLiteral(") "));
+ _console->write(getSenderHeader(sender));
auto ret = _console->machine()->executeCode(code);
_console->appendCommandPrompt();
_console->setMode(ScriptingConsole::Input);
return ret;
}
+QString WingAngelAPI::getSenderHeader(const WingHex::SenderInfo &sender) {
+ return QStringLiteral("(") % sender.puid % QStringLiteral("::") %
+ sender.plgcls % QStringLiteral(") ");
+}
+
QString WingAngelAPI::_InputBox_getItem(int stringID, const QString &title,
const QString &label,
const CScriptArray &items, int current,
@@ -1923,25 +1972,28 @@ bool WingAngelAPI::_HexController_appendBytes(const CScriptArray &ba) {
}
bool WingAngelAPI::_DataVisual_updateTextList(int stringID,
- const CScriptArray &data) {
+ const CScriptArray &data,
+ const QString &title) {
bool o = false;
auto ret = cArray2QStringList(data, stringID, &o);
if (o) {
- return emit visual.updateTextList(ret);
+ return emit visual.updateTextList(ret, title);
} else {
return false;
}
}
-bool WingAngelAPI::_DataVisual_updateTextTable(
- int stringID, const QString &json, const CScriptArray &headers,
- const CScriptArray &headerNames) {
+bool WingAngelAPI::_DataVisual_updateTextTable(int stringID,
+ const QString &json,
+ const CScriptArray &headers,
+ const CScriptArray &headerNames,
+ const QString &title) {
bool o = false;
auto h = cArray2QStringList(headers, stringID, &o);
if (o) {
auto hn = cArray2QStringList(headerNames, stringID, &o);
if (o) {
- return emit visual.updateTextTable(json, h, hn);
+ return emit visual.updateTextTable(json, h, hn, title);
} else {
return false;
}
diff --git a/src/class/wingangelapi.h b/src/class/wingangelapi.h
index 461b590..5ece4dd 100644
--- a/src/class/wingangelapi.h
+++ b/src/class/wingangelapi.h
@@ -52,6 +52,10 @@ public:
registerScriptFns(const QString &ns,
const QHash &rfns);
+ void
+ registerScriptEnums(const QString &ns,
+ const QHash>> &objs);
+
void installAPI(ScriptMachine *machine);
ScriptingConsole *bindingConsole() const;
@@ -69,6 +73,7 @@ private:
void installHexControllerAPI(asIScriptEngine *engine);
void installDataVisualAPI(asIScriptEngine *engine, int stringID);
void installScriptFns(asIScriptEngine *engine);
+ void installScriptEnums(asIScriptEngine *engine);
private:
template
@@ -122,9 +127,14 @@ private:
static void script_call(asIScriptGeneric *gen);
private:
- WING_SERVICE bool execScriptCode(const QString &code);
- WING_SERVICE bool execScript(const QString &fileName);
- WING_SERVICE bool execCode(const QString &code);
+ WING_SERVICE bool execScriptCode(const WingHex::SenderInfo &sender,
+ const QString &code);
+ WING_SERVICE bool execScript(const WingHex::SenderInfo &sender,
+ const QString &fileName);
+ WING_SERVICE bool execCode(const WingHex::SenderInfo &sender,
+ const QString &code);
+
+ QString getSenderHeader(const WingHex::SenderInfo &sender);
private:
QString _InputBox_getItem(int stringID, const QString &title,
@@ -164,11 +174,13 @@ private:
bool _HexController_appendBytes(const CScriptArray &ba);
- bool _DataVisual_updateTextList(int stringID, const CScriptArray &data);
+ bool _DataVisual_updateTextList(int stringID, const CScriptArray &data,
+ const QString &title);
bool _DataVisual_updateTextTable(int stringID, const QString &json,
const CScriptArray &headers,
- const CScriptArray &headerNames);
+ const CScriptArray &headerNames,
+ const QString &title);
private:
std::vector _fnbuffer;
@@ -177,6 +189,7 @@ private:
ScriptingConsole *_console = nullptr;
QHash> _rfns;
+ QHash>>> _objs;
};
#endif // WINGANGELAPI_H
diff --git a/src/control/editorview.cpp b/src/control/editorview.cpp
index e9f0591..654d60c 100644
--- a/src/control/editorview.cpp
+++ b/src/control/editorview.cpp
@@ -210,26 +210,20 @@ EditorView::FindError EditorView::find(const FindDialog::Result &result) {
m_findResults->clear();
auto lineWidth = m_hex->renderer()->hexLineWidth();
+ auto docLen = d->length();
for (auto &ritem : results) {
FindResult r;
r.offset = ritem;
r.line = r.offset / lineWidth;
r.col = r.offset % lineWidth;
m_findResults->results().append(r);
-
- QString content;
- QByteArray buffer;
- // TODO
- FindResultModel::FindInfo info;
-
- // default show lineWidth count
- if (data.size() > lineWidth - 4) {
- }
-
- info.decoding = Utilities::decodingString(buffer, result.encoding);
- m_findResults->lastFindData().append(info);
+ m_findResults->findData().append(
+ readContextFinding(ritem, data.size(), FIND_CONTEXT_SIZE,
+ FIND_MAX_DISPLAY_FIND_CHARS));
}
+ m_findResults->lastFindData() = data;
+
m_findResults->endUpdate();
if (m_findResults->size() ==
@@ -612,6 +606,37 @@ QHash EditorView::savePluginData() {
return ret;
}
+FindResultModel::FindInfo EditorView::readContextFinding(qsizetype offset,
+ qsizetype findSize,
+ int contextSize,
+ int maxDisplayBytes) {
+ auto doc = m_hex->document();
+
+ qsizetype halfSize = maxDisplayBytes / 2;
+ auto header = doc->read(offset, qMin(findSize, halfSize));
+ QByteArray tailer;
+ if (header.size() < findSize) {
+ tailer = doc->read(
+ offset, qMin(findSize, qsizetype(maxDisplayBytes) - halfSize));
+ }
+
+ auto left = qsizetype(maxDisplayBytes) - header.size() - tailer.size();
+
+ // append to contextSize
+ contextSize += (left / 2);
+
+ auto cheader = doc->read(offset - contextSize, contextSize);
+ auto ctailer = doc->read(offset + findSize, contextSize);
+
+ FindResultModel::FindInfo info;
+ info.cheader = cheader;
+ info.hbuffer = header;
+ info.tbuffer = tailer;
+ info.ctailer = ctailer;
+
+ return info;
+}
+
EditorView *EditorView::cloneParent() const { return m_cloneParent; }
bool EditorView::isCloned() const { return m_cloneParent != nullptr; }
diff --git a/src/control/editorview.h b/src/control/editorview.h
index 41842fb..9b2caa2 100644
--- a/src/control/editorview.h
+++ b/src/control/editorview.h
@@ -125,6 +125,11 @@ private:
void applyPluginData(const QHash &data);
QHash savePluginData();
+ FindResultModel::FindInfo readContextFinding(qsizetype offset,
+ qsizetype findSize,
+ int contextSize,
+ int maxDisplayBytes);
+
private:
template
inline void newAction(QWidget *parent, const QString &icon,
diff --git a/src/dialog/finddialog.cpp b/src/dialog/finddialog.cpp
index a0490f9..f529cf9 100644
--- a/src/dialog/finddialog.cpp
+++ b/src/dialog/finddialog.cpp
@@ -67,14 +67,14 @@ FindDialog::FindDialog(const FindInfo &info, QWidget *parent)
if (info.isStringFind) {
m_string->setChecked(true);
m_lineeditor->setEnabled(true);
- m_hex->setEnabled(false);
+ m_hexeditor->setEnabled(false);
if (!info.encoding.isEmpty()) {
m_encodings->setCurrentText(info.encoding);
}
} else {
m_hex->setChecked(true);
m_lineeditor->setEnabled(false);
- m_hex->setEnabled(true);
+ m_hexeditor->setEnabled(true);
}
m_lineeditor->setText(info.str);
diff --git a/src/dialog/mainwindow.cpp b/src/dialog/mainwindow.cpp
index e7c87bf..9c597ed 100644
--- a/src/dialog/mainwindow.cpp
+++ b/src/dialog/mainwindow.cpp
@@ -24,6 +24,7 @@
#include "aboutsoftwaredialog.h"
#include "checksumdialog.h"
#include "class/appmanager.h"
+#include "class/eventfilter.h"
#include "class/langservice.h"
#include "class/languagemanager.h"
#include "class/layoutmanager.h"
@@ -480,6 +481,7 @@ MainWindow::buildUpFindResultDock(ads::CDockManager *dock,
m_findresult->setProperty("EditorView", quintptr(0));
Utilities::applyTableViewProperty(m_findresult);
+ auto header = m_findresult->horizontalHeader();
m_findresult->setContextMenuPolicy(
Qt::ContextMenuPolicy::ActionsContextMenu);
@@ -494,6 +496,9 @@ MainWindow::buildUpFindResultDock(ads::CDockManager *dock,
m_findresult->setModel(_findEmptyResult);
+ header->setSectionResizeMode(3, QHeaderView::Stretch);
+ header->setSectionResizeMode(4, QHeaderView::Stretch);
+
connect(m_findresult, &QTableView::doubleClicked, this,
[=](const QModelIndex &index) {
auto editor =
@@ -779,6 +784,29 @@ MainWindow::buildUpVisualDataDock(ads::CDockManager *dock,
ads::CDockAreaWidget *areaw) {
using namespace ads;
+ auto efilter = new EventFilter(QEvent::DynamicPropertyChange, this);
+ connect(efilter, &EventFilter::eventTriggered, this,
+ [this](QObject *obj, QEvent *event) {
+ auto e = static_cast(event);
+ constexpr auto ppname = "__TITLE__";
+ if (e->propertyName() == QByteArray(ppname)) {
+ auto title = obj->property(ppname).toString();
+ auto display = obj->property("__DISPLAY__").toString();
+ auto dock = reinterpret_cast(
+ obj->property("__DOCK__").value());
+ if (dock) {
+ if (!title.isEmpty()) {
+ display += QStringLiteral("(") % title %
+ QStringLiteral(")");
+ }
+ dock->setWindowTitle(display);
+ }
+ }
+ });
+
+ constexpr auto dpname = "__DISPLAY__";
+ constexpr auto dockpname = "__DOCK__";
+
m_infolist = new QListView(this);
m_infolist->setEditTriggers(QListView::EditTrigger::NoEditTriggers);
connect(m_infolist, &QListView::clicked, this,
@@ -795,6 +823,10 @@ MainWindow::buildUpVisualDataDock(ads::CDockManager *dock,
});
auto dw = buildDockWidget(dock, QStringLiteral("DVList"), tr("DVList"),
m_infolist);
+ m_infolist->setProperty(dpname, tr("DVList"));
+ m_infolist->setProperty(dockpname, quintptr(dw));
+ m_infolist->installEventFilter(efilter);
+
auto ar = dock->addDockWidget(area, dw, areaw);
m_infotree = new QTreeView(this);
@@ -813,6 +845,9 @@ MainWindow::buildUpVisualDataDock(ads::CDockManager *dock,
});
dw = buildDockWidget(dock, QStringLiteral("DVTree"), tr("DVTree"),
m_infotree);
+ m_infotree->setProperty(dpname, tr("DVTree"));
+ m_infotree->setProperty(dockpname, quintptr(dw));
+ m_infotree->installEventFilter(efilter);
dock->addDockWidget(CenterDockWidgetArea, dw, ar);
m_infotable = new QTableView(this);
@@ -831,11 +866,17 @@ MainWindow::buildUpVisualDataDock(ads::CDockManager *dock,
});
dw = buildDockWidget(dock, QStringLiteral("DVTable"), tr("DVTable"),
m_infotable);
+ m_infotable->setProperty(dpname, tr("DVTable"));
+ m_infotable->setProperty(dockpname, quintptr(dw));
+ m_infotable->installEventFilter(efilter);
dock->addDockWidget(CenterDockWidgetArea, dw, ar);
m_infotxt = new QTextBrowser(this);
dw = buildDockWidget(dock, QStringLiteral("DVText"), tr("DVText"),
m_infotxt);
+ m_infotxt->setProperty(dpname, tr("DVText"));
+ m_infotxt->setProperty(dockpname, quintptr(dw));
+ m_infotxt->installEventFilter(efilter);
dock->addDockWidget(CenterDockWidgetArea, dw, ar);
return ar;
@@ -2270,8 +2311,8 @@ void MainWindow::on_exportfindresult() {
tr("EmptyFindResult"));
return;
}
- auto filename = WingFileDialog::getSaveFileName(this, tr("ChooseSaveFile"),
- m_lastusedpath);
+ auto filename = WingFileDialog::getSaveFileName(
+ this, tr("ChooseSaveFile"), m_lastusedpath, {"Json (*.json)"});
if (filename.isEmpty())
return;
m_lastusedpath = QFileInfo(filename).absoluteDir().absolutePath();
@@ -2281,9 +2322,10 @@ void MainWindow::on_exportfindresult() {
QJsonObject fobj;
fobj.insert(QStringLiteral("file"), editor->fileName());
- // auto d= findresitem->lastFindData();
+ auto d = findresitem->lastFindData();
- // fobj.insert(QStringLiteral("data"), findresitem->lastFindData());
+ fobj.insert(QStringLiteral("find"),
+ QString::fromLatin1(d.toHex(' ').toUpper()));
QJsonArray arr;
for (int i = 0; i < c; i++) {
auto data = findresitem->resultAt(i);
@@ -2291,6 +2333,18 @@ void MainWindow::on_exportfindresult() {
jobj.insert(QStringLiteral("line"), QString::number(data.line));
jobj.insert(QStringLiteral("col"), QString::number(data.col));
jobj.insert(QStringLiteral("offset"), QString::number(data.offset));
+
+ QTextDocument doc;
+ doc.setHtml(
+ findresitem->data(findresitem->index(i, 3), Qt::DisplayRole)
+ .toString());
+ jobj.insert(QStringLiteral("range"), doc.toPlainText());
+
+ doc.setHtml(
+ findresitem->data(findresitem->index(i, 4), Qt::DisplayRole)
+ .toString());
+ jobj.insert(QStringLiteral("encoding"), doc.toPlainText());
+
arr.append(jobj);
}
fobj.insert(QStringLiteral("data"), arr);
diff --git a/src/dialog/scriptingdialog.cpp b/src/dialog/scriptingdialog.cpp
index 919fcc1..7e5bd3b 100644
--- a/src/dialog/scriptingdialog.cpp
+++ b/src/dialog/scriptingdialog.cpp
@@ -629,6 +629,7 @@ ScriptingDialog::buildSymbolShowDock(ads::CDockManager *dock,
ads::CDockAreaWidget *areaw) {
Q_ASSERT(m_consoleout);
m_sym = new ASObjTreeWidget(this);
+ m_sym->header()->setSectionResizeMode(QHeaderView::Stretch);
auto dw =
buildDockWidget(dock, QStringLiteral("Symbol"), tr("Symbol"), m_sym);
return dock->addDockWidget(area, dw, areaw);
diff --git a/src/model/findresultmodel.cpp b/src/model/findresultmodel.cpp
index de02ec0..47d594e 100644
--- a/src/model/findresultmodel.cpp
+++ b/src/model/findresultmodel.cpp
@@ -16,9 +16,10 @@
*/
#include "findresultmodel.h"
+#include "utilities.h"
FindResultModel::FindResultModel(QObject *parent)
- : QAbstractTableModel(parent) {}
+ : QAbstractTableModel(parent), m_encoding(QStringLiteral("ASCII")) {}
int FindResultModel::rowCount(const QModelIndex &parent) const {
Q_UNUSED(parent);
@@ -43,15 +44,53 @@ QVariant FindResultModel::data(const QModelIndex &index, int role) const {
case 2: // offset
return QStringLiteral("0x") +
QString::number(r.offset, 16).toUpper();
- case 3: // range
- return m_lastFindData.at(row).findRange;
- case 4: // decoding
- return m_lastFindData.at(row).decoding;
+ case 3: {
+ // range
+ auto data = m_findData.at(row);
+ QString buffer =
+ data.cheader.toHex(' ').toUpper() % QStringLiteral(" ");
+ if (!data.hbuffer.isEmpty()) {
+ buffer += data.hbuffer.toHex(' ').toUpper();
+ if (!data.tbuffer.isEmpty()) {
+ buffer += QStringLiteral(" .. ");
+ }
+ }
+
+ buffer += data.tbuffer.toHex(' ').toUpper() %
+ QStringLiteral(" ") %
+ data.ctailer.toHex(' ').toUpper();
+
+ return buffer;
+ }
+ case 4: { // decoding
+ auto data = m_findData.at(row);
+ QString buffer =
+ Utilities::decodingString(data.cheader, m_encoding) %
+ QStringLiteral(" ");
+ if (!data.hbuffer.isEmpty()) {
+ buffer += Utilities::decodingString(data.hbuffer);
+ if (!data.tbuffer.isEmpty()) {
+ buffer += QStringLiteral(" ... ");
+ }
+ }
+
+ buffer += Utilities::decodingString(data.tbuffer) %
+ QStringLiteral(" ") %
+ Utilities::decodingString(data.ctailer);
+
+ return buffer;
+ }
}
return QVariant();
}
case Qt::TextAlignmentRole:
- return Qt::AlignCenter;
+ switch (index.column()) {
+ case 3:
+ case 4:
+ return Qt::AlignLeft;
+ default:
+ return Qt::AlignCenter;
+ }
}
return QVariant();
}
@@ -79,12 +118,20 @@ QVariant FindResultModel::headerData(int section, Qt::Orientation orientation,
return QVariant();
}
+QString FindResultModel::encoding() const { return m_encoding; }
+
+void FindResultModel::setEncoding(const QString &newEncoding) {
+ m_encoding = newEncoding;
+}
+
QList &FindResultModel::results() { return m_results; }
-QList &FindResultModel::lastFindData() {
- return m_lastFindData;
+QList &FindResultModel::findData() {
+ return m_findData;
}
+QByteArray &FindResultModel::lastFindData() { return m_lastFindData; }
+
void FindResultModel::beginUpdate() { this->beginResetModel(); }
void FindResultModel::endUpdate() { this->endResetModel(); }
@@ -95,7 +142,7 @@ WingHex::FindResult FindResultModel::resultAt(qsizetype index) const {
void FindResultModel::clear() {
m_results.clear();
- m_lastFindData.clear();
+ m_findData.clear();
}
QList::size_type FindResultModel::size() const {
diff --git a/src/model/findresultmodel.h b/src/model/findresultmodel.h
index 301b281..a549ca9 100644
--- a/src/model/findresultmodel.h
+++ b/src/model/findresultmodel.h
@@ -24,17 +24,21 @@
class FindResultModel : public QAbstractTableModel {
Q_OBJECT
+
public:
struct FindInfo {
- QString findRange;
- QString decoding;
+ QByteArray cheader;
+ QByteArray hbuffer;
+ QByteArray tbuffer;
+ QByteArray ctailer;
};
public:
explicit FindResultModel(QObject *parent = nullptr);
QList &results();
- QList &lastFindData();
+ QList &findData();
+ QByteArray &lastFindData();
void beginUpdate();
void endUpdate();
@@ -51,9 +55,15 @@ public:
virtual QVariant headerData(int section, Qt::Orientation orientation,
int role) const override;
+ QString encoding() const;
+ void setEncoding(const QString &newEncoding);
+
private:
QList m_results;
- QList m_lastFindData;
+ QList m_findData;
+ QByteArray m_lastFindData;
+
+ QString m_encoding;
};
#endif // FINDRESULTMODEL_H
diff --git a/src/plugin/iwingplugin.h b/src/plugin/iwingplugin.h
index 79e49ba..09a6139 100644
--- a/src/plugin/iwingplugin.h
+++ b/src/plugin/iwingplugin.h
@@ -401,30 +401,32 @@ public:
typedef ClickedCallBack DoubleClickedCallBack;
signals:
- bool updateText(const QString &data);
- bool updateTextList(const QStringList &data, ClickedCallBack clicked = {},
+ bool updateText(const QString &data, const QString &title = {});
+ bool updateTextList(const QStringList &data, const QString &title = {},
+ ClickedCallBack clicked = {},
DoubleClickedCallBack dblClicked = {});
Q_REQUIRED_RESULT bool
- updateTextTree(const QString &json, ClickedCallBack clicked = {},
+ updateTextTree(const QString &json, const QString &title = {},
+ ClickedCallBack clicked = {},
DoubleClickedCallBack dblClicked = {});
Q_REQUIRED_RESULT bool
updateTextTable(const QString &json, const QStringList &headers,
const QStringList &headerNames = {},
- ClickedCallBack clicked = {},
+ const QString &title = {}, ClickedCallBack clicked = {},
DoubleClickedCallBack dblClicked = {});
// API for Qt Plugin Only
Q_REQUIRED_RESULT bool
- updateTextListByModel(QAbstractItemModel *model,
+ updateTextListByModel(QAbstractItemModel *model, const QString &title = {},
ClickedCallBack clicked = {},
DoubleClickedCallBack dblClicked = {});
Q_REQUIRED_RESULT bool
- updateTextTableByModel(QAbstractItemModel *model,
+ updateTextTableByModel(QAbstractItemModel *model, const QString &title = {},
ClickedCallBack clicked = {},
DoubleClickedCallBack dblClicked = {});
Q_REQUIRED_RESULT bool
- updateTextTreeByModel(QAbstractItemModel *model,
+ updateTextTreeByModel(QAbstractItemModel *model, const QString &title = {},
ClickedCallBack clicked = {},
DoubleClickedCallBack dblClicked = {});
};
@@ -494,7 +496,13 @@ signals:
struct WingDependency {
QString puid;
uint version;
- QString md5; // optional, but recommend
+ QByteArray md5; // optional, but recommend
+};
+
+struct SenderInfo {
+ QString plgcls;
+ QString puid;
+ QVariant meta;
};
#ifdef WING_SERVICE
@@ -602,8 +610,9 @@ public:
return {};
}
- // QHash< obj-names, decl-members >
- virtual QHash registeredScriptObjs() const {
+ // QHash< enum , members >
+ virtual QHash>>
+ registeredScriptEnums() const {
return {};
}
@@ -655,8 +664,7 @@ signals:
QGenericArgument val5 = QGenericArgument(),
QGenericArgument val6 = QGenericArgument(),
QGenericArgument val7 = QGenericArgument(),
- QGenericArgument val8 = QGenericArgument(),
- QGenericArgument val9 = QGenericArgument());
+ QGenericArgument val8 = QGenericArgument());
public:
inline bool invokeService(const QString &puid, const char *member,
@@ -669,11 +677,10 @@ public:
QGenericArgument val5 = QGenericArgument(),
QGenericArgument val6 = QGenericArgument(),
QGenericArgument val7 = QGenericArgument(),
- QGenericArgument val8 = QGenericArgument(),
- QGenericArgument val9 = QGenericArgument()) {
+ QGenericArgument val8 = QGenericArgument()) {
return emit invokeService(puid, member, Qt::AutoConnection, ret, val0,
val1, val2, val3, val4, val5, val6, val7,
- val8, val9);
+ val8);
}
inline bool invokeService(const QString &puid, const char *member,
@@ -685,11 +692,10 @@ public:
QGenericArgument val5 = QGenericArgument(),
QGenericArgument val6 = QGenericArgument(),
QGenericArgument val7 = QGenericArgument(),
- QGenericArgument val8 = QGenericArgument(),
- QGenericArgument val9 = QGenericArgument()) {
+ QGenericArgument val8 = QGenericArgument()) {
return emit invokeService(puid, member, type, QGenericReturnArgument(),
val0, val1, val2, val3, val4, val5, val6,
- val7, val8, val9);
+ val7, val8);
}
inline bool invokeService(const QString &puid, const char *member,
@@ -701,11 +707,10 @@ public:
QGenericArgument val5 = QGenericArgument(),
QGenericArgument val6 = QGenericArgument(),
QGenericArgument val7 = QGenericArgument(),
- QGenericArgument val8 = QGenericArgument(),
- QGenericArgument val9 = QGenericArgument()) {
+ QGenericArgument val8 = QGenericArgument()) {
return emit invokeService(puid, member, Qt::AutoConnection,
QGenericReturnArgument(), val0, val1, val2,
- val3, val4, val5, val6, val7, val8, val9);
+ val3, val4, val5, val6, val7, val8);
}
public:
@@ -720,6 +725,7 @@ public:
} // namespace WingHex
+Q_DECLARE_METATYPE(WingHex::SenderInfo)
Q_DECLARE_INTERFACE(WingHex::IWingPlugin, "com.wingsummer.iwingplugin")
#endif // IWINGPLUGIN_H
diff --git a/src/plugin/pluginsystem.cpp b/src/plugin/pluginsystem.cpp
index fb848d8..331ee66 100644
--- a/src/plugin/pluginsystem.cpp
+++ b/src/plugin/pluginsystem.cpp
@@ -68,15 +68,14 @@ void PluginSystem::loadPlugin(const QFileInfo &fileinfo, const QDir &setdir) {
Q_ASSERT(_win);
if (fileinfo.exists()) {
- QPluginLoader loader(fileinfo.absoluteFilePath(), this);
+ auto fileName = fileinfo.absoluteFilePath();
+ QPluginLoader loader(fileName, this);
Logger::info(tr("LoadingPlugin") + fileinfo.fileName());
auto p = qobject_cast(loader.instance());
if (Q_UNLIKELY(p == nullptr)) {
Logger::critical(loader.errorString());
} else {
- if (!loadPlugin(p, setdir)) {
- loader.unload();
- }
+ loadPlugin(p, fileName, setdir);
}
Logger::_log("");
}
@@ -299,6 +298,17 @@ void PluginSystem::registerFns(IWingPlugin *plg) {
_angelplg->registerScriptFns(plg->metaObject()->className(), rfns);
}
+void PluginSystem::registerEnums(IWingPlugin *plg) {
+ Q_ASSERT(plg);
+ auto objs = plg->registeredScriptEnums();
+ if (objs.isEmpty()) {
+ return;
+ }
+
+ Q_ASSERT(_angelplg);
+ _angelplg->registerScriptEnums(plg->metaObject()->className(), objs);
+}
+
void PluginSystem::registerEvents(IWingPlugin *plg) {
Q_ASSERT(plg);
auto evs = plg->registeredEvents();
@@ -445,15 +455,35 @@ QString PluginSystem::getScriptFnSig(const QString &fnName,
QString PluginSystem::getPUID(IWingPlugin *p) {
if (p) {
+ constexpr auto puid_limit = 36; // same as uuid length, so enough
auto prop = p->property("puid").toString().trimmed();
+ if (prop.length() > puid_limit) {
+ return {};
+ }
auto pid = QString(p->metaObject()->className());
+ if (pid.length() > puid_limit) {
+ return {};
+ }
return prop.isEmpty() ? pid : prop;
} else {
return {};
}
}
-bool PluginSystem::loadPlugin(IWingPlugin *p,
+bool PluginSystem::isPluginLoaded(const WingDependency &d) {
+ for (auto &info : _loadedplginfo) {
+ if (info.version >= d.version && info.puid == d.puid) {
+ if (d.md5.isEmpty()) {
+ return true;
+ } else {
+ return d.md5.compare(info.md5, Qt::CaseInsensitive) == 0;
+ }
+ }
+ }
+ return false;
+}
+
+void PluginSystem::loadPlugin(IWingPlugin *p, const QString &fileName,
const std::optional &setdir) {
QTranslator *p_tr = nullptr;
@@ -471,8 +501,25 @@ bool PluginSystem::loadPlugin(IWingPlugin *p,
}
auto puid = getPUID(p);
- if (_loadedpuid.contains(puid)) {
- throw tr("ErrLoadLoadedPlugin");
+ if (puid.isEmpty()) {
+ throw tr("ErrLoadInvalidPUID");
+ }
+
+ for (auto &uid : _loadedplginfo) {
+ if (uid.puid == puid) {
+ throw tr("ErrLoadLoadedPlugin");
+ }
+ }
+
+ // check dependencise
+ auto dps = p->dependencies();
+ if (!dps.isEmpty()) {
+ for (auto &d : dps) {
+ if (!isPluginLoaded(d)) {
+ _lazyplgs.append(qMakePair(p, fileName));
+ return;
+ }
+ }
}
emit pluginLoading(p->pluginName());
@@ -496,8 +543,14 @@ bool PluginSystem::loadPlugin(IWingPlugin *p,
}
}
- _loadedplgs.push_back(p);
- _loadedpuid << puid;
+ _loadedplgs.append(p);
+
+ WingDependency de;
+ de.puid = puid;
+ de.version = p->pluginVersion();
+ de.md5 = Utilities::getMd5(fileName);
+
+ _loadedplginfo.append(de);
Logger::warning(tr("PluginName :") + p->pluginName());
Logger::warning(tr("PluginAuthor :") + p->pluginAuthor());
@@ -665,6 +718,7 @@ bool PluginSystem::loadPlugin(IWingPlugin *p,
}
registerFns(p);
+ registerEnums(p);
registerEvents(p);
connectInterface(p);
@@ -674,9 +728,7 @@ bool PluginSystem::loadPlugin(IWingPlugin *p,
if (p_tr) {
p_tr->deleteLater();
}
- return false;
}
- return true;
}
void PluginSystem::connectInterface(IWingPlugin *plg) {
@@ -738,22 +790,22 @@ void PluginSystem::connectBaseInterface(IWingPlugin *plg) {
QGenericReturnArgument, QGenericArgument, QGenericArgument,
QGenericArgument, QGenericArgument, QGenericArgument,
QGenericArgument, QGenericArgument, QGenericArgument,
- QGenericArgument,
QGenericArgument>::of(&IWingPlugin::invokeService),
this,
[=](const QString &puid, const char *method, Qt::ConnectionType type,
QGenericReturnArgument ret, QGenericArgument val0,
QGenericArgument val1, QGenericArgument val2, QGenericArgument val3,
QGenericArgument val4, QGenericArgument val5, QGenericArgument val6,
- QGenericArgument val7, QGenericArgument val8,
- QGenericArgument val9) -> bool {
+ QGenericArgument val7, QGenericArgument val8) -> bool {
auto r = std::find_if(
_loadedplgs.begin(), _loadedplgs.end(),
[=](IWingPlugin *plg) { return getPUID(plg) == puid; });
if (r == _loadedplgs.end()) {
return false;
}
- auto meta = (*r)->metaObject();
+
+ auto obj = *r;
+ auto meta = obj->metaObject();
// filter the evil call and report to log
QVarLengthArray sig;
@@ -762,10 +814,13 @@ void PluginSystem::connectBaseInterface(IWingPlugin *plg) {
return false;
sig.append(method, len);
sig.append('(');
- const char *typeNames[] = {ret.name(), val0.name(), val1.name(),
- val2.name(), val3.name(), val4.name(),
- val5.name(), val6.name(), val7.name(),
- val8.name(), val9.name()};
+
+ auto sname = QMetaType::fromType().name();
+
+ const char *typeNames[] = {ret.name(), sname, val0.name(),
+ val1.name(), val2.name(), val3.name(),
+ val4.name(), val5.name(), val6.name(),
+ val7.name(), val8.name()};
size_t paramCount;
constexpr auto maxParamCount =
sizeof(typeNames) / sizeof(const char *);
@@ -803,10 +858,26 @@ void PluginSystem::connectBaseInterface(IWingPlugin *plg) {
return false;
}
- auto obj = *r;
- obj->setProperty("__LAST_CALLER__", plg->metaObject()->className());
- return m.invoke(obj, type, ret, val0, val1, val2, val3, val4, val5,
- val6, val7, val8, val9);
+ meta = plg->metaObject();
+ SenderInfo info;
+ info.plgcls = meta->className();
+ info.puid = getPUID(plg);
+
+ auto meta_name = "WING_META";
+ // property first
+ auto var = plg->property(meta_name);
+ if (var.isValid()) {
+ info.meta = var;
+ } else {
+ auto iidx = meta->indexOfClassInfo(meta_name);
+ if (iidx >= 0) {
+ info.meta = QString(meta->classInfo(iidx).value());
+ }
+ }
+
+ return m.invoke(obj, type, ret,
+ WINGAPI_ARG(WingHex::SenderInfo, info), val0, val1,
+ val2, val3, val4, val5, val6, val7, val8);
});
}
@@ -2152,13 +2223,14 @@ void PluginSystem::connectUIInterface(IWingPlugin *plg) {
auto visual = &plg->visual;
connect(visual, &WingPlugin::DataVisual::updateText, _win,
- [=](const QString &txt) -> bool {
+ [=](const QString &txt, const QString &title) -> bool {
+ _win->m_infotxt->setProperty("__TITLE__", title);
_win->m_infotxt->setText(txt);
return true;
});
connect(
visual, &WingPlugin::DataVisual::updateTextList, _win,
- [=](const QStringList &data,
+ [=](const QStringList &data, const QString &title,
WingHex::WingPlugin::DataVisual::ClickedCallBack clicked,
WingHex::WingPlugin::DataVisual::DoubleClickedCallBack dblClicked)
-> bool {
@@ -2166,6 +2238,7 @@ void PluginSystem::connectUIInterface(IWingPlugin *plg) {
if (oldmodel) {
oldmodel->deleteLater();
}
+ _win->m_infolist->setProperty("__TITLE__", title);
auto model = new QStringListModel(data);
_win->m_infolist->setModel(model);
_win->m_infoclickfn = clicked;
@@ -2174,7 +2247,7 @@ void PluginSystem::connectUIInterface(IWingPlugin *plg) {
});
connect(
visual, &WingPlugin::DataVisual::updateTextListByModel, _win,
- [=](QAbstractItemModel *model,
+ [=](QAbstractItemModel *model, const QString &title,
WingHex::WingPlugin::DataVisual::ClickedCallBack clicked,
WingHex::WingPlugin::DataVisual::DoubleClickedCallBack dblClicked)
-> bool {
@@ -2183,6 +2256,7 @@ void PluginSystem::connectUIInterface(IWingPlugin *plg) {
if (oldmodel) {
oldmodel->deleteLater();
}
+ _win->m_infolist->setProperty("__TITLE__", title);
_win->m_infolist->setModel(model);
_win->m_infoclickfn = clicked;
_win->m_infodblclickfn = dblClicked;
@@ -2192,7 +2266,7 @@ void PluginSystem::connectUIInterface(IWingPlugin *plg) {
});
connect(
visual, &WingPlugin::DataVisual::updateTextTree, _win,
- [=](const QString &json,
+ [=](const QString &json, const QString &title,
WingHex::WingPlugin::DataVisual::ClickedCallBack clicked,
WingHex::WingPlugin::DataVisual::DoubleClickedCallBack dblClicked)
-> bool {
@@ -2200,6 +2274,7 @@ void PluginSystem::connectUIInterface(IWingPlugin *plg) {
if (oldmodel) {
oldmodel->deleteLater();
}
+ _win->m_infotree->setProperty("__TITLE__", title);
auto model = new QJsonModel;
if (model->loadJson(json.toUtf8())) {
_win->m_infotree->setModel(model);
@@ -2211,7 +2286,7 @@ void PluginSystem::connectUIInterface(IWingPlugin *plg) {
});
connect(
visual, &WingPlugin::DataVisual::updateTextTreeByModel, _win,
- [=](QAbstractItemModel *model,
+ [=](QAbstractItemModel *model, const QString &title,
WingHex::WingPlugin::DataVisual::ClickedCallBack clicked,
WingHex::WingPlugin::DataVisual::DoubleClickedCallBack dblClicked)
-> bool {
@@ -2220,6 +2295,7 @@ void PluginSystem::connectUIInterface(IWingPlugin *plg) {
if (oldmodel) {
oldmodel->deleteLater();
}
+ _win->m_infotree->setProperty("__TITLE__", title);
_win->m_infotree->setModel(model);
_win->m_infotreeclickfn = clicked;
_win->m_infotreedblclickfn = dblClicked;
@@ -2230,7 +2306,7 @@ void PluginSystem::connectUIInterface(IWingPlugin *plg) {
connect(
visual, &WingPlugin::DataVisual::updateTextTable, _win,
[=](const QString &json, const QStringList &headers,
- const QStringList &headerNames,
+ const QStringList &headerNames, const QString &title,
WingHex::WingPlugin::DataVisual::ClickedCallBack clicked,
WingHex::WingPlugin::DataVisual::DoubleClickedCallBack dblClicked)
-> bool {
@@ -2257,7 +2333,7 @@ void PluginSystem::connectUIInterface(IWingPlugin *plg) {
header.append(heading);
}
}
-
+ _win->m_infotable->setProperty("__TITLE__", title);
auto model = new QJsonTableModel(header);
model->setJson(QJsonDocument::fromJson(json.toUtf8()));
_win->m_infotable->setModel(model);
@@ -2267,7 +2343,7 @@ void PluginSystem::connectUIInterface(IWingPlugin *plg) {
});
connect(
visual, &WingPlugin::DataVisual::updateTextTableByModel, _win,
- [=](QAbstractItemModel *model,
+ [=](QAbstractItemModel *model, const QString &title,
WingHex::WingPlugin::DataVisual::ClickedCallBack clicked,
WingHex::WingPlugin::DataVisual::DoubleClickedCallBack dblClicked)
-> bool {
@@ -2276,6 +2352,7 @@ void PluginSystem::connectUIInterface(IWingPlugin *plg) {
if (oldmodel) {
oldmodel->deleteLater();
}
+ _win->m_infotable->setProperty("__TITLE__", title);
_win->m_infotable->setModel(model);
_win->m_infotableclickfn = clicked;
_win->m_infotabledblclickfn = dblClicked;
@@ -2313,9 +2390,7 @@ void PluginSystem::LoadPlugin() {
if (set.scriptEnabled()) {
_angelplg = new WingAngelAPI;
- auto ret = loadPlugin(_angelplg, std::nullopt);
- Q_ASSERT(ret);
- Q_UNUSED(ret);
+ loadPlugin(_angelplg, {}, std::nullopt);
}
bool ok;
@@ -2370,6 +2445,33 @@ void PluginSystem::LoadPlugin() {
loadPlugin(item, udir);
}
+ if (!_lazyplgs.isEmpty()) {
+ decltype(_lazyplgs) lazyplgs;
+ lazyplgs.swap(_lazyplgs);
+
+ for (auto &item : lazyplgs) {
+ loadPlugin(item.first, item.second, udir);
+ }
+ }
+
+ if (!_lazyplgs.isEmpty()) {
+ Logger::critical(tr("PluginLoadingFailedSummary"));
+ Logger::_log({});
+ for (auto &lplg : _lazyplgs) {
+ auto plg = lplg.first;
+ Logger::critical(tr("- PluginName:") + plg->pluginName());
+ Logger::critical(tr("- Dependencies:"));
+ for (auto &d : plg->dependencies()) {
+ Logger::critical(QString(4, ' ') + tr("PUID:") + d.puid);
+ Logger::critical(QString(4, ' ') + tr("Version:") +
+ QString::number(d.version));
+ Logger::critical(QString(4, ' ') + tr("MD5:") + d.md5);
+ }
+ plg->deleteLater();
+ }
+ _lazyplgs.clear();
+ }
+
Logger::info(tr("PluginLoadingFinished"));
}
diff --git a/src/plugin/pluginsystem.h b/src/plugin/pluginsystem.h
index 6415388..9da89ea 100644
--- a/src/plugin/pluginsystem.h
+++ b/src/plugin/pluginsystem.h
@@ -126,6 +126,7 @@ public:
private:
void registerFns(IWingPlugin *plg);
+ void registerEnums(IWingPlugin *plg);
void registerEvents(IWingPlugin *plg);
QString type2AngelScriptString(IWingPlugin::MetaType type, bool isArg);
@@ -135,8 +136,11 @@ private:
QString getPUID(IWingPlugin *p);
+ bool isPluginLoaded(const WingDependency &d);
+
private:
- bool loadPlugin(IWingPlugin *p, const std::optional &setdir);
+ void loadPlugin(IWingPlugin *p, const QString &fileName,
+ const std::optional &setdir);
void connectInterface(IWingPlugin *plg);
void connectLoadingInterface(IWingPlugin *plg);
@@ -230,8 +234,9 @@ private:
private:
MainWindow *_win = nullptr;
- QStringList _loadedpuid;
+ QList _loadedplginfo;
QList _loadedplgs;
+ QList> _lazyplgs;
QMap> _evplgs;
diff --git a/src/utilities.h b/src/utilities.h
index aaf9849..61444b9 100644
--- a/src/utilities.h
+++ b/src/utilities.h
@@ -50,6 +50,9 @@
#define PROEXT ".wingpro"
+constexpr auto FIND_CONTEXT_SIZE = 3;
+constexpr auto FIND_MAX_DISPLAY_FIND_CHARS = 8;
+
Q_DECL_UNUSED static inline QString NAMEICONRES(const QString &name) {
return ":/com.wingsummer.winghex/images/" + name + ".png";
}
@@ -156,6 +159,10 @@ public:
}
static QByteArray getMd5(QString filename) {
+ if (filename.isEmpty()) {
+ return {};
+ }
+
QFile sourceFile(filename);
if (sourceFile.open(QIODevice::ReadOnly)) {
QCryptographicHash hash(QCryptographicHash::Md5);
@@ -163,7 +170,7 @@ public:
return hash.result();
}
}
- return QByteArray();
+ return {};
}
static bool checkIsLittleEndian() {