feat: 完善插件系统和功能;修复增强查找功能;增加可视化自定义标题;
This commit is contained in:
parent
3e21be134c
commit
b66f802c3a
|
@ -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);
|
||||
|
|
|
@ -287,28 +287,28 @@
|
|||
<translation>数据可视化</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../testform.cpp" line="345"/>
|
||||
<location filename="../testform.cpp" line="355"/>
|
||||
<location filename="../testform.cpp" line="348"/>
|
||||
<location filename="../testform.cpp" line="359"/>
|
||||
<source>UpdateTextTreeError</source>
|
||||
<translation>更新文本树失败</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../testform.cpp" line="370"/>
|
||||
<location filename="../testform.cpp" line="374"/>
|
||||
<source>UpdateTextListByModelError</source>
|
||||
<translation>通过模型更新文本列表失败</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../testform.cpp" line="380"/>
|
||||
<location filename="../testform.cpp" line="384"/>
|
||||
<source>UpdateTextTableByModelError</source>
|
||||
<translation>通过模型更新文本表格失败</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../testform.cpp" line="391"/>
|
||||
<location filename="../testform.cpp" line="395"/>
|
||||
<source>UpdateTextTreeByModelError</source>
|
||||
<translation>通过模型更新文本树失败</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../testform.cpp" line="492"/>
|
||||
<location filename="../testform.cpp" line="496"/>
|
||||
<source>Choose</source>
|
||||
<translation>选择</translation>
|
||||
</message>
|
||||
|
|
|
@ -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"));
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
** =============================================================================
|
||||
*/
|
||||
|
||||
#include "richtextitemdelegate.h"
|
||||
|
||||
#include <QAbstractTextDocumentLayout>
|
||||
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
** =============================================================================
|
||||
*/
|
||||
|
||||
#ifndef RICHTEXTITEMDELEGATE_H
|
||||
#define RICHTEXTITEMDELEGATE_H
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -80,6 +80,17 @@ const QString WingAngelAPI::pluginComment() const {
|
|||
"ability to call the host API.");
|
||||
}
|
||||
|
||||
void WingAngelAPI::registerScriptEnums(
|
||||
const QString &ns, const QHash<QString, QList<QPair<QString, int>>> &objs) {
|
||||
Q_ASSERT(!ns.isEmpty());
|
||||
if (objs.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check it later
|
||||
_objs.insert(ns, objs);
|
||||
}
|
||||
|
||||
void WingAngelAPI::registerScriptFns(const QString &ns,
|
||||
const QHash<QString, ScriptFnInfo> &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<bool(const QString &)>(
|
||||
registerAPI<bool(const QString &, const QString &)>(
|
||||
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<bool(const CScriptArray &)>(
|
||||
registerAPI<bool(const CScriptArray &, const QString &)>(
|
||||
engine,
|
||||
std::bind(&WingAngelAPI::_DataVisual_updateTextList, this, stringID,
|
||||
std::placeholders::_1),
|
||||
"bool updateTextList(array<string> &in data)");
|
||||
std::placeholders::_1, std::placeholders::_2),
|
||||
"bool updateTextList(array<string> &in data, string &in title=\"\")");
|
||||
|
||||
registerAPI<bool(const QString &)>(
|
||||
registerAPI<bool(const QString &, const QString &)>(
|
||||
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<bool(const QString &, const CScriptArray &,
|
||||
const CScriptArray &)>(
|
||||
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<string> &in headers, "
|
||||
"array<string> &in headerNames = array<string>())");
|
||||
"array<string> &in headerNames = array<string>(), 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;
|
||||
}
|
||||
|
|
|
@ -52,6 +52,10 @@ public:
|
|||
registerScriptFns(const QString &ns,
|
||||
const QHash<QString, IWingPlugin::ScriptFnInfo> &rfns);
|
||||
|
||||
void
|
||||
registerScriptEnums(const QString &ns,
|
||||
const QHash<QString, QList<QPair<QString, int>>> &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 <class T>
|
||||
|
@ -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<std::any> _fnbuffer;
|
||||
|
@ -177,6 +189,7 @@ private:
|
|||
ScriptingConsole *_console = nullptr;
|
||||
|
||||
QHash<QString, QHash<QString, qsizetype>> _rfns;
|
||||
QHash<QString, QHash<QString, QList<QPair<QString, int>>>> _objs;
|
||||
};
|
||||
|
||||
#endif // WINGANGELAPI_H
|
||||
|
|
|
@ -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<QString, QByteArray> 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; }
|
||||
|
|
|
@ -125,6 +125,11 @@ private:
|
|||
void applyPluginData(const QHash<QString, QByteArray> &data);
|
||||
QHash<QString, QByteArray> savePluginData();
|
||||
|
||||
FindResultModel::FindInfo readContextFinding(qsizetype offset,
|
||||
qsizetype findSize,
|
||||
int contextSize,
|
||||
int maxDisplayBytes);
|
||||
|
||||
private:
|
||||
template <typename Func>
|
||||
inline void newAction(QWidget *parent, const QString &icon,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<QDynamicPropertyChangeEvent *>(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<QDockWidget *>(
|
||||
obj->property("__DOCK__").value<quintptr>());
|
||||
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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(" <b>");
|
||||
if (!data.hbuffer.isEmpty()) {
|
||||
buffer += data.hbuffer.toHex(' ').toUpper();
|
||||
if (!data.tbuffer.isEmpty()) {
|
||||
buffer += QStringLiteral(" .. ");
|
||||
}
|
||||
}
|
||||
|
||||
buffer += data.tbuffer.toHex(' ').toUpper() %
|
||||
QStringLiteral("</b> ") %
|
||||
data.ctailer.toHex(' ').toUpper();
|
||||
|
||||
return buffer;
|
||||
}
|
||||
case 4: { // decoding
|
||||
auto data = m_findData.at(row);
|
||||
QString buffer =
|
||||
Utilities::decodingString(data.cheader, m_encoding) %
|
||||
QStringLiteral(" <b>");
|
||||
if (!data.hbuffer.isEmpty()) {
|
||||
buffer += Utilities::decodingString(data.hbuffer);
|
||||
if (!data.tbuffer.isEmpty()) {
|
||||
buffer += QStringLiteral(" ... ");
|
||||
}
|
||||
}
|
||||
|
||||
buffer += Utilities::decodingString(data.tbuffer) %
|
||||
QStringLiteral("</b> ") %
|
||||
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<WingHex::FindResult> &FindResultModel::results() { return m_results; }
|
||||
|
||||
QList<FindResultModel::FindInfo> &FindResultModel::lastFindData() {
|
||||
return m_lastFindData;
|
||||
QList<FindResultModel::FindInfo> &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<WingHex::FindResult>::size_type FindResultModel::size() const {
|
||||
|
|
|
@ -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<WingHex::FindResult> &results();
|
||||
QList<FindInfo> &lastFindData();
|
||||
QList<FindInfo> &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<WingHex::FindResult> m_results;
|
||||
QList<FindInfo> m_lastFindData;
|
||||
QList<FindInfo> m_findData;
|
||||
QByteArray m_lastFindData;
|
||||
|
||||
QString m_encoding;
|
||||
};
|
||||
|
||||
#endif // FINDRESULTMODEL_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<QString, QStringList> registeredScriptObjs() const {
|
||||
// QHash< enum , members >
|
||||
virtual QHash<QString, QList<QPair<QString, int>>>
|
||||
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
|
||||
|
|
|
@ -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<IWingPlugin *>(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<QDir> &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<char, 512> 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<WingHex::SenderInfo>().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"));
|
||||
}
|
||||
|
||||
|
|
|
@ -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<QDir> &setdir);
|
||||
void loadPlugin(IWingPlugin *p, const QString &fileName,
|
||||
const std::optional<QDir> &setdir);
|
||||
|
||||
void connectInterface(IWingPlugin *plg);
|
||||
void connectLoadingInterface(IWingPlugin *plg);
|
||||
|
@ -230,8 +234,9 @@ private:
|
|||
|
||||
private:
|
||||
MainWindow *_win = nullptr;
|
||||
QStringList _loadedpuid;
|
||||
QList<WingDependency> _loadedplginfo;
|
||||
QList<IWingPlugin *> _loadedplgs;
|
||||
QList<QPair<IWingPlugin *, QString>> _lazyplgs;
|
||||
|
||||
QMap<IWingPlugin::RegisteredEvent, QList<IWingPlugin *>> _evplgs;
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Reference in New Issue