feat: 完善插件系统和功能;修复增强查找功能;增加可视化自定义标题;

This commit is contained in:
寂静的羽夏 2025-01-01 20:43:49 +08:00
parent 3e21be134c
commit b66f802c3a
21 changed files with 901 additions and 470 deletions

View File

@ -128,7 +128,7 @@ private:
signals: signals:
void documentChanged(QHexDocument *doc); void documentChanged(QHexDocument *doc);
void cursorLocationChanged(); void cursorLocationChanged();
void cursorSelectionChanged(); // TODO void cursorSelectionChanged();
void canUndoChanged(bool canUndo); void canUndoChanged(bool canUndo);
void canRedoChanged(bool canRedo); void canRedoChanged(bool canRedo);
void documentSaved(bool saved); void documentSaved(bool saved);

View File

@ -287,28 +287,28 @@
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../testform.cpp" line="345"/> <location filename="../testform.cpp" line="348"/>
<location filename="../testform.cpp" line="355"/> <location filename="../testform.cpp" line="359"/>
<source>UpdateTextTreeError</source> <source>UpdateTextTreeError</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../testform.cpp" line="370"/> <location filename="../testform.cpp" line="374"/>
<source>UpdateTextListByModelError</source> <source>UpdateTextListByModelError</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../testform.cpp" line="380"/> <location filename="../testform.cpp" line="384"/>
<source>UpdateTextTableByModelError</source> <source>UpdateTextTableByModelError</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../testform.cpp" line="391"/> <location filename="../testform.cpp" line="395"/>
<source>UpdateTextTreeByModelError</source> <source>UpdateTextTreeByModelError</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../testform.cpp" line="492"/> <location filename="../testform.cpp" line="496"/>
<source>Choose</source> <source>Choose</source>
<translation></translation> <translation></translation>
</message> </message>

View File

@ -329,16 +329,19 @@ void TestForm::on_btnGetColor_clicked() {
} }
void TestForm::on_btnText_2_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() { void TestForm::on_btnTextList_clicked() {
auto txts = ui->teDataVisual->toPlainText().split('\n'); 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() { void TestForm::on_btnTextTree_clicked() {
auto ret = emit _plg->visual.updateTextTree(ui->teDataVisual->toPlainText(), auto ret = emit _plg->visual.updateTextTree(ui->teDataVisual->toPlainText(),
QStringLiteral("TestForm"),
_click, _dblclick); _click, _dblclick);
if (!ret) { if (!ret) {
emit _plg->msgbox.critical(this, QStringLiteral("Test"), emit _plg->msgbox.critical(this, QStringLiteral("Test"),
@ -349,7 +352,8 @@ void TestForm::on_btnTextTree_clicked() {
void TestForm::on_btnTextTable_clicked() { void TestForm::on_btnTextTable_clicked() {
auto ret = emit _plg->visual.updateTextTable( auto ret = emit _plg->visual.updateTextTable(
ui->teDataVisual->toPlainText(), ui->teDataVisual->toPlainText(),
{WingHex::WINGSUMMER, WingHex::WINGSUMMER}, {}, _click, _dblclick); {WingHex::WINGSUMMER, WingHex::WINGSUMMER}, {},
QStringLiteral("TestForm"), _click, _dblclick);
if (!ret) { if (!ret) {
emit _plg->msgbox.critical(this, QStringLiteral("Test"), emit _plg->msgbox.critical(this, QStringLiteral("Test"),
tr("UpdateTextTreeError")); tr("UpdateTextTreeError"));
@ -363,8 +367,8 @@ void TestForm::on_btnTextListByModel_clicked() {
buffer.append(WingHex::WINGSUMMER % QString::number(i)); buffer.append(WingHex::WINGSUMMER % QString::number(i));
} }
model->setStringList(buffer); model->setStringList(buffer);
auto ret = auto ret = emit _plg->visual.updateTextListByModel(
emit _plg->visual.updateTextListByModel(model, _click, _dblclick); model, QStringLiteral("TestForm"), _click, _dblclick);
if (!ret) { if (!ret) {
emit _plg->msgbox.critical(this, QStringLiteral("Test"), emit _plg->msgbox.critical(this, QStringLiteral("Test"),
tr("UpdateTextListByModelError")); tr("UpdateTextListByModelError"));
@ -373,8 +377,8 @@ void TestForm::on_btnTextListByModel_clicked() {
void TestForm::on_btnTextTableByModel_clicked() { void TestForm::on_btnTextTableByModel_clicked() {
auto model = new TestTableModel; auto model = new TestTableModel;
auto ret = auto ret = emit _plg->visual.updateTextTableByModel(
emit _plg->visual.updateTextTableByModel(model, _click, _dblclick); model, QStringLiteral("TestForm"), _click, _dblclick);
if (!ret) { if (!ret) {
emit _plg->msgbox.critical(this, QStringLiteral("Test"), emit _plg->msgbox.critical(this, QStringLiteral("Test"),
tr("UpdateTextTableByModelError")); tr("UpdateTextTableByModelError"));
@ -384,8 +388,8 @@ void TestForm::on_btnTextTableByModel_clicked() {
void TestForm::on_btnTextTreeByModel_clicked() { void TestForm::on_btnTextTreeByModel_clicked() {
auto model = new QFileSystemModel; auto model = new QFileSystemModel;
model->setRootPath(QDir::currentPath()); model->setRootPath(QDir::currentPath());
auto ret = auto ret = emit _plg->visual.updateTextTreeByModel(
emit _plg->visual.updateTextTreeByModel(model, _click, _dblclick); model, QStringLiteral("TestForm"), _click, _dblclick);
if (!ret) { if (!ret) {
emit _plg->msgbox.critical(this, QStringLiteral("Test"), emit _plg->msgbox.critical(this, QStringLiteral("Test"),
tr("UpdateTextTreeByModelError")); tr("UpdateTextTreeByModelError"));

File diff suppressed because it is too large Load Diff

View File

@ -186,7 +186,7 @@ void AsCompletion::complete(const QDocumentCursor &c, const QString &trigger) {
return; return;
} }
} else if (rbegin->content == DOT_TRIGGER) { } else if (rbegin->content == DOT_TRIGGER) {
// TODO // TODO only PR
} else { } else {
applyEmptyNsNode(nodes); applyEmptyNsNode(nodes);
} }

View File

@ -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 "richtextitemdelegate.h"
#include <QAbstractTextDocumentLayout> #include <QAbstractTextDocumentLayout>
@ -11,44 +28,64 @@ RichTextItemDelegate::RichTextItemDelegate(QObject *parent)
void RichTextItemDelegate::paint(QPainter *painter, void RichTextItemDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option, const QStyleOptionViewItem &option,
const QModelIndex &index) const { const QModelIndex &index) const {
auto options = option; if (!index.isValid())
initStyleOption(&options, index); 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; QTextDocument doc;
doc.setHtml(options.text); doc.setHtml(text);
options.text.clear(); // Disable word wrapping
options.widget->style()->drawControl(QStyle::CE_ItemViewItem, &options, QTextOption textOption;
painter); textOption.setWrapMode(QTextOption::NoWrap);
doc.setDefaultTextOption(textOption);
// shift text right to make icon visible // Clip the painter to the cell rectangle
QSize iconSize = options.icon.actualSize(options.rect.size()); painter->save();
painter->translate(options.rect.left() + iconSize.width(), painter->setClipRect(option.rect);
options.rect.top());
QRect clip(0, 0, options.rect.width() + iconSize.width(),
options.rect.height());
painter->setClipRect(clip); // Calculate the rendering rectangle based on alignment
QAbstractTextDocumentLayout::PaintContext ctx; QRect rect = option.rect;
// set text color to red for selected item QSize contentSize = doc.size().toSize();
if (option.state & QStyle::State_Selected) if (alignment & Qt::AlignHCenter) {
ctx.palette.setColor(QPalette::Text, Qt::red); rect.setLeft(rect.left() + (rect.width() - contentSize.width()) / 2);
} else if (alignment & Qt::AlignRight) {
rect.setLeft(rect.right() - contentSize.width());
}
ctx.clip = clip; if (alignment & Qt::AlignVCenter) {
doc.documentLayout()->draw(painter, ctx); 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(); painter->restore();
} }
QSize RichTextItemDelegate::sizeHint(const QStyleOptionViewItem &option, QSize RichTextItemDelegate::sizeHint(const QStyleOptionViewItem &option,
const QModelIndex &index) const { const QModelIndex &index) const {
auto options = option; QString text = index.data(Qt::DisplayRole).toString();
initStyleOption(&options, index); if (text.isEmpty())
return QStyledItemDelegate::sizeHint(option, index);
QTextDocument doc; QTextDocument doc;
doc.setHtml(options.text); doc.setHtml(text);
doc.setTextWidth(options.rect.width()); doc.setTextWidth(option.rect.width());
return QSize(doc.idealWidth(), doc.size().height()); return doc.size().toSize();
} }

View File

@ -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 #ifndef RICHTEXTITEMDELEGATE_H
#define RICHTEXTITEMDELEGATE_H #define RICHTEXTITEMDELEGATE_H

View File

@ -186,9 +186,6 @@ bool ScriptConsoleMachine::execString(asIScriptEngine *engine,
info.message = str; info.message = str;
emit onOutput(MessageType::Info, info); emit onOutput(MessageType::Info, info);
return true; return true;
} else if (code.startsWith(QStringLiteral("import "))) {
// TODO
return true;
} else { } else {
return ExecuteString(engine, code.toUtf8(), mod, immediateContext()) >= return ExecuteString(engine, code.toUtf8(), mod, immediateContext()) >=
0; 0;

View File

@ -80,6 +80,17 @@ const QString WingAngelAPI::pluginComment() const {
"ability to call the host API."); "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, void WingAngelAPI::registerScriptFns(const QString &ns,
const QHash<QString, ScriptFnInfo> &rfns) { const QHash<QString, ScriptFnInfo> &rfns) {
Q_ASSERT(!ns.isEmpty()); Q_ASSERT(!ns.isEmpty());
@ -115,6 +126,7 @@ void WingAngelAPI::installAPI(ScriptMachine *machine) {
installDataVisualAPI(engine, stringTypeID); installDataVisualAPI(engine, stringTypeID);
installScriptFns(engine); installScriptFns(engine);
installScriptEnums(engine);
} }
void WingAngelAPI::installLogAPI(asIScriptEngine *engine) { void WingAngelAPI::installLogAPI(asIScriptEngine *engine) {
@ -1107,34 +1119,35 @@ void WingAngelAPI::installDataVisualAPI(asIScriptEngine *engine, int stringID) {
auto datavis = &this->visual; auto datavis = &this->visual;
registerAPI<bool(const QString &)>( registerAPI<bool(const QString &, const QString &)>(
engine, engine,
std::bind(&WingHex::WingPlugin::DataVisual::updateText, datavis, std::bind(&WingHex::WingPlugin::DataVisual::updateText, datavis,
std::placeholders::_1), std::placeholders::_1, std::placeholders::_2),
"bool updateText(string &in data)"); "bool updateText(string &in data, string &in title=\"\")");
registerAPI<bool(const CScriptArray &)>( registerAPI<bool(const CScriptArray &, const QString &)>(
engine, engine,
std::bind(&WingAngelAPI::_DataVisual_updateTextList, this, stringID, std::bind(&WingAngelAPI::_DataVisual_updateTextList, this, stringID,
std::placeholders::_1), std::placeholders::_1, std::placeholders::_2),
"bool updateTextList(array<string> &in data)"); "bool updateTextList(array<string> &in data, string &in title=\"\")");
registerAPI<bool(const QString &)>( registerAPI<bool(const QString &, const QString &)>(
engine, engine,
std::bind(&WingHex::WingPlugin::DataVisual::updateTextTree, datavis, std::bind(&WingHex::WingPlugin::DataVisual::updateTextTree, datavis,
std::placeholders::_1, std::placeholders::_1, std::placeholders::_2,
WingHex::WingPlugin::DataVisual::ClickedCallBack(), WingHex::WingPlugin::DataVisual::ClickedCallBack(),
WingHex::WingPlugin::DataVisual::DoubleClickedCallBack()), WingHex::WingPlugin::DataVisual::DoubleClickedCallBack()),
"bool updateTextTree(string &in json)"); "bool updateTextTree(string &in json, string &in title=\"\")");
registerAPI<bool(const QString &, const CScriptArray &, registerAPI<bool(const QString &, const CScriptArray &,
const CScriptArray &)>( const CScriptArray &, const QString &)>(
engine, engine,
std::bind(&WingAngelAPI::_DataVisual_updateTextTable, this, stringID, std::bind(&WingAngelAPI::_DataVisual_updateTextTable, this, stringID,
std::placeholders::_1, std::placeholders::_2, std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3), std::placeholders::_3, std::placeholders::_4),
"bool updateTextTable(string &in json, array<string> &in headers, " "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(""); 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, QStringList WingAngelAPI::cArray2QStringList(const CScriptArray &array,
int stringID, bool *ok) { int stringID, bool *ok) {
bool b = array.GetElementTypeId() == stringID; 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)); 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()) { if (code.isEmpty()) {
return true; return true;
} }
@ -1666,9 +1714,7 @@ bool WingAngelAPI::execScriptCode(const QString &code) {
} }
_console->setMode(ScriptingConsole::Output); _console->setMode(ScriptingConsole::Output);
_console->write(QStringLiteral("(") % _console->write(getSenderHeader(sender));
property("__LAST_CALLER__").toString() %
QStringLiteral(") "));
_console->machine()->executeScript(f.fileName()); _console->machine()->executeScript(f.fileName());
_console->appendCommandPrompt(); _console->appendCommandPrompt();
_console->setMode(ScriptingConsole::Input); _console->setMode(ScriptingConsole::Input);
@ -1677,28 +1723,31 @@ bool WingAngelAPI::execScriptCode(const QString &code) {
return false; return false;
} }
bool WingAngelAPI::execScript(const QString &fileName) { bool WingAngelAPI::execScript(const WingHex::SenderInfo &sender,
const QString &fileName) {
_console->setMode(ScriptingConsole::Output); _console->setMode(ScriptingConsole::Output);
_console->write(QStringLiteral("(") % _console->write(getSenderHeader(sender));
property("__LAST_CALLER__").toString() %
QStringLiteral(") "));
auto ret = _console->machine()->executeScript(fileName); auto ret = _console->machine()->executeScript(fileName);
_console->appendCommandPrompt(); _console->appendCommandPrompt();
_console->setMode(ScriptingConsole::Input); _console->setMode(ScriptingConsole::Input);
return ret; return ret;
} }
bool WingAngelAPI::execCode(const QString &code) { bool WingAngelAPI::execCode(const WingHex::SenderInfo &sender,
const QString &code) {
_console->setMode(ScriptingConsole::Output); _console->setMode(ScriptingConsole::Output);
_console->write(QStringLiteral("(") % _console->write(getSenderHeader(sender));
property("__LAST_CALLER__").toString() %
QStringLiteral(") "));
auto ret = _console->machine()->executeCode(code); auto ret = _console->machine()->executeCode(code);
_console->appendCommandPrompt(); _console->appendCommandPrompt();
_console->setMode(ScriptingConsole::Input); _console->setMode(ScriptingConsole::Input);
return ret; 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, QString WingAngelAPI::_InputBox_getItem(int stringID, const QString &title,
const QString &label, const QString &label,
const CScriptArray &items, int current, const CScriptArray &items, int current,
@ -1923,25 +1972,28 @@ bool WingAngelAPI::_HexController_appendBytes(const CScriptArray &ba) {
} }
bool WingAngelAPI::_DataVisual_updateTextList(int stringID, bool WingAngelAPI::_DataVisual_updateTextList(int stringID,
const CScriptArray &data) { const CScriptArray &data,
const QString &title) {
bool o = false; bool o = false;
auto ret = cArray2QStringList(data, stringID, &o); auto ret = cArray2QStringList(data, stringID, &o);
if (o) { if (o) {
return emit visual.updateTextList(ret); return emit visual.updateTextList(ret, title);
} else { } else {
return false; return false;
} }
} }
bool WingAngelAPI::_DataVisual_updateTextTable( bool WingAngelAPI::_DataVisual_updateTextTable(int stringID,
int stringID, const QString &json, const CScriptArray &headers, const QString &json,
const CScriptArray &headerNames) { const CScriptArray &headers,
const CScriptArray &headerNames,
const QString &title) {
bool o = false; bool o = false;
auto h = cArray2QStringList(headers, stringID, &o); auto h = cArray2QStringList(headers, stringID, &o);
if (o) { if (o) {
auto hn = cArray2QStringList(headerNames, stringID, &o); auto hn = cArray2QStringList(headerNames, stringID, &o);
if (o) { if (o) {
return emit visual.updateTextTable(json, h, hn); return emit visual.updateTextTable(json, h, hn, title);
} else { } else {
return false; return false;
} }

View File

@ -52,6 +52,10 @@ public:
registerScriptFns(const QString &ns, registerScriptFns(const QString &ns,
const QHash<QString, IWingPlugin::ScriptFnInfo> &rfns); const QHash<QString, IWingPlugin::ScriptFnInfo> &rfns);
void
registerScriptEnums(const QString &ns,
const QHash<QString, QList<QPair<QString, int>>> &objs);
void installAPI(ScriptMachine *machine); void installAPI(ScriptMachine *machine);
ScriptingConsole *bindingConsole() const; ScriptingConsole *bindingConsole() const;
@ -69,6 +73,7 @@ private:
void installHexControllerAPI(asIScriptEngine *engine); void installHexControllerAPI(asIScriptEngine *engine);
void installDataVisualAPI(asIScriptEngine *engine, int stringID); void installDataVisualAPI(asIScriptEngine *engine, int stringID);
void installScriptFns(asIScriptEngine *engine); void installScriptFns(asIScriptEngine *engine);
void installScriptEnums(asIScriptEngine *engine);
private: private:
template <class T> template <class T>
@ -122,9 +127,14 @@ private:
static void script_call(asIScriptGeneric *gen); static void script_call(asIScriptGeneric *gen);
private: private:
WING_SERVICE bool execScriptCode(const QString &code); WING_SERVICE bool execScriptCode(const WingHex::SenderInfo &sender,
WING_SERVICE bool execScript(const QString &fileName); const QString &code);
WING_SERVICE bool execCode(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: private:
QString _InputBox_getItem(int stringID, const QString &title, QString _InputBox_getItem(int stringID, const QString &title,
@ -164,11 +174,13 @@ private:
bool _HexController_appendBytes(const CScriptArray &ba); 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, bool _DataVisual_updateTextTable(int stringID, const QString &json,
const CScriptArray &headers, const CScriptArray &headers,
const CScriptArray &headerNames); const CScriptArray &headerNames,
const QString &title);
private: private:
std::vector<std::any> _fnbuffer; std::vector<std::any> _fnbuffer;
@ -177,6 +189,7 @@ private:
ScriptingConsole *_console = nullptr; ScriptingConsole *_console = nullptr;
QHash<QString, QHash<QString, qsizetype>> _rfns; QHash<QString, QHash<QString, qsizetype>> _rfns;
QHash<QString, QHash<QString, QList<QPair<QString, int>>>> _objs;
}; };
#endif // WINGANGELAPI_H #endif // WINGANGELAPI_H

View File

@ -210,26 +210,20 @@ EditorView::FindError EditorView::find(const FindDialog::Result &result) {
m_findResults->clear(); m_findResults->clear();
auto lineWidth = m_hex->renderer()->hexLineWidth(); auto lineWidth = m_hex->renderer()->hexLineWidth();
auto docLen = d->length();
for (auto &ritem : results) { for (auto &ritem : results) {
FindResult r; FindResult r;
r.offset = ritem; r.offset = ritem;
r.line = r.offset / lineWidth; r.line = r.offset / lineWidth;
r.col = r.offset % lineWidth; r.col = r.offset % lineWidth;
m_findResults->results().append(r); m_findResults->results().append(r);
m_findResults->findData().append(
QString content; readContextFinding(ritem, data.size(), FIND_CONTEXT_SIZE,
QByteArray buffer; FIND_MAX_DISPLAY_FIND_CHARS));
// 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->lastFindData() = data;
m_findResults->endUpdate(); m_findResults->endUpdate();
if (m_findResults->size() == if (m_findResults->size() ==
@ -612,6 +606,37 @@ QHash<QString, QByteArray> EditorView::savePluginData() {
return ret; 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; } EditorView *EditorView::cloneParent() const { return m_cloneParent; }
bool EditorView::isCloned() const { return m_cloneParent != nullptr; } bool EditorView::isCloned() const { return m_cloneParent != nullptr; }

View File

@ -125,6 +125,11 @@ private:
void applyPluginData(const QHash<QString, QByteArray> &data); void applyPluginData(const QHash<QString, QByteArray> &data);
QHash<QString, QByteArray> savePluginData(); QHash<QString, QByteArray> savePluginData();
FindResultModel::FindInfo readContextFinding(qsizetype offset,
qsizetype findSize,
int contextSize,
int maxDisplayBytes);
private: private:
template <typename Func> template <typename Func>
inline void newAction(QWidget *parent, const QString &icon, inline void newAction(QWidget *parent, const QString &icon,

View File

@ -67,14 +67,14 @@ FindDialog::FindDialog(const FindInfo &info, QWidget *parent)
if (info.isStringFind) { if (info.isStringFind) {
m_string->setChecked(true); m_string->setChecked(true);
m_lineeditor->setEnabled(true); m_lineeditor->setEnabled(true);
m_hex->setEnabled(false); m_hexeditor->setEnabled(false);
if (!info.encoding.isEmpty()) { if (!info.encoding.isEmpty()) {
m_encodings->setCurrentText(info.encoding); m_encodings->setCurrentText(info.encoding);
} }
} else { } else {
m_hex->setChecked(true); m_hex->setChecked(true);
m_lineeditor->setEnabled(false); m_lineeditor->setEnabled(false);
m_hex->setEnabled(true); m_hexeditor->setEnabled(true);
} }
m_lineeditor->setText(info.str); m_lineeditor->setText(info.str);

View File

@ -24,6 +24,7 @@
#include "aboutsoftwaredialog.h" #include "aboutsoftwaredialog.h"
#include "checksumdialog.h" #include "checksumdialog.h"
#include "class/appmanager.h" #include "class/appmanager.h"
#include "class/eventfilter.h"
#include "class/langservice.h" #include "class/langservice.h"
#include "class/languagemanager.h" #include "class/languagemanager.h"
#include "class/layoutmanager.h" #include "class/layoutmanager.h"
@ -480,6 +481,7 @@ MainWindow::buildUpFindResultDock(ads::CDockManager *dock,
m_findresult->setProperty("EditorView", quintptr(0)); m_findresult->setProperty("EditorView", quintptr(0));
Utilities::applyTableViewProperty(m_findresult); Utilities::applyTableViewProperty(m_findresult);
auto header = m_findresult->horizontalHeader();
m_findresult->setContextMenuPolicy( m_findresult->setContextMenuPolicy(
Qt::ContextMenuPolicy::ActionsContextMenu); Qt::ContextMenuPolicy::ActionsContextMenu);
@ -494,6 +496,9 @@ MainWindow::buildUpFindResultDock(ads::CDockManager *dock,
m_findresult->setModel(_findEmptyResult); m_findresult->setModel(_findEmptyResult);
header->setSectionResizeMode(3, QHeaderView::Stretch);
header->setSectionResizeMode(4, QHeaderView::Stretch);
connect(m_findresult, &QTableView::doubleClicked, this, connect(m_findresult, &QTableView::doubleClicked, this,
[=](const QModelIndex &index) { [=](const QModelIndex &index) {
auto editor = auto editor =
@ -779,6 +784,29 @@ MainWindow::buildUpVisualDataDock(ads::CDockManager *dock,
ads::CDockAreaWidget *areaw) { ads::CDockAreaWidget *areaw) {
using namespace ads; 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 = new QListView(this);
m_infolist->setEditTriggers(QListView::EditTrigger::NoEditTriggers); m_infolist->setEditTriggers(QListView::EditTrigger::NoEditTriggers);
connect(m_infolist, &QListView::clicked, this, connect(m_infolist, &QListView::clicked, this,
@ -795,6 +823,10 @@ MainWindow::buildUpVisualDataDock(ads::CDockManager *dock,
}); });
auto dw = buildDockWidget(dock, QStringLiteral("DVList"), tr("DVList"), auto dw = buildDockWidget(dock, QStringLiteral("DVList"), tr("DVList"),
m_infolist); 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); auto ar = dock->addDockWidget(area, dw, areaw);
m_infotree = new QTreeView(this); m_infotree = new QTreeView(this);
@ -813,6 +845,9 @@ MainWindow::buildUpVisualDataDock(ads::CDockManager *dock,
}); });
dw = buildDockWidget(dock, QStringLiteral("DVTree"), tr("DVTree"), dw = buildDockWidget(dock, QStringLiteral("DVTree"), tr("DVTree"),
m_infotree); m_infotree);
m_infotree->setProperty(dpname, tr("DVTree"));
m_infotree->setProperty(dockpname, quintptr(dw));
m_infotree->installEventFilter(efilter);
dock->addDockWidget(CenterDockWidgetArea, dw, ar); dock->addDockWidget(CenterDockWidgetArea, dw, ar);
m_infotable = new QTableView(this); m_infotable = new QTableView(this);
@ -831,11 +866,17 @@ MainWindow::buildUpVisualDataDock(ads::CDockManager *dock,
}); });
dw = buildDockWidget(dock, QStringLiteral("DVTable"), tr("DVTable"), dw = buildDockWidget(dock, QStringLiteral("DVTable"), tr("DVTable"),
m_infotable); m_infotable);
m_infotable->setProperty(dpname, tr("DVTable"));
m_infotable->setProperty(dockpname, quintptr(dw));
m_infotable->installEventFilter(efilter);
dock->addDockWidget(CenterDockWidgetArea, dw, ar); dock->addDockWidget(CenterDockWidgetArea, dw, ar);
m_infotxt = new QTextBrowser(this); m_infotxt = new QTextBrowser(this);
dw = buildDockWidget(dock, QStringLiteral("DVText"), tr("DVText"), dw = buildDockWidget(dock, QStringLiteral("DVText"), tr("DVText"),
m_infotxt); m_infotxt);
m_infotxt->setProperty(dpname, tr("DVText"));
m_infotxt->setProperty(dockpname, quintptr(dw));
m_infotxt->installEventFilter(efilter);
dock->addDockWidget(CenterDockWidgetArea, dw, ar); dock->addDockWidget(CenterDockWidgetArea, dw, ar);
return ar; return ar;
@ -2270,8 +2311,8 @@ void MainWindow::on_exportfindresult() {
tr("EmptyFindResult")); tr("EmptyFindResult"));
return; return;
} }
auto filename = WingFileDialog::getSaveFileName(this, tr("ChooseSaveFile"), auto filename = WingFileDialog::getSaveFileName(
m_lastusedpath); this, tr("ChooseSaveFile"), m_lastusedpath, {"Json (*.json)"});
if (filename.isEmpty()) if (filename.isEmpty())
return; return;
m_lastusedpath = QFileInfo(filename).absoluteDir().absolutePath(); m_lastusedpath = QFileInfo(filename).absoluteDir().absolutePath();
@ -2281,9 +2322,10 @@ void MainWindow::on_exportfindresult() {
QJsonObject fobj; QJsonObject fobj;
fobj.insert(QStringLiteral("file"), editor->fileName()); 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; QJsonArray arr;
for (int i = 0; i < c; i++) { for (int i = 0; i < c; i++) {
auto data = findresitem->resultAt(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("line"), QString::number(data.line));
jobj.insert(QStringLiteral("col"), QString::number(data.col)); jobj.insert(QStringLiteral("col"), QString::number(data.col));
jobj.insert(QStringLiteral("offset"), QString::number(data.offset)); 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); arr.append(jobj);
} }
fobj.insert(QStringLiteral("data"), arr); fobj.insert(QStringLiteral("data"), arr);

View File

@ -629,6 +629,7 @@ ScriptingDialog::buildSymbolShowDock(ads::CDockManager *dock,
ads::CDockAreaWidget *areaw) { ads::CDockAreaWidget *areaw) {
Q_ASSERT(m_consoleout); Q_ASSERT(m_consoleout);
m_sym = new ASObjTreeWidget(this); m_sym = new ASObjTreeWidget(this);
m_sym->header()->setSectionResizeMode(QHeaderView::Stretch);
auto dw = auto dw =
buildDockWidget(dock, QStringLiteral("Symbol"), tr("Symbol"), m_sym); buildDockWidget(dock, QStringLiteral("Symbol"), tr("Symbol"), m_sym);
return dock->addDockWidget(area, dw, areaw); return dock->addDockWidget(area, dw, areaw);

View File

@ -16,9 +16,10 @@
*/ */
#include "findresultmodel.h" #include "findresultmodel.h"
#include "utilities.h"
FindResultModel::FindResultModel(QObject *parent) FindResultModel::FindResultModel(QObject *parent)
: QAbstractTableModel(parent) {} : QAbstractTableModel(parent), m_encoding(QStringLiteral("ASCII")) {}
int FindResultModel::rowCount(const QModelIndex &parent) const { int FindResultModel::rowCount(const QModelIndex &parent) const {
Q_UNUSED(parent); Q_UNUSED(parent);
@ -43,15 +44,53 @@ QVariant FindResultModel::data(const QModelIndex &index, int role) const {
case 2: // offset case 2: // offset
return QStringLiteral("0x") + return QStringLiteral("0x") +
QString::number(r.offset, 16).toUpper(); QString::number(r.offset, 16).toUpper();
case 3: // range case 3: {
return m_lastFindData.at(row).findRange; // range
case 4: // decoding auto data = m_findData.at(row);
return m_lastFindData.at(row).decoding; 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(); return QVariant();
} }
case Qt::TextAlignmentRole: case Qt::TextAlignmentRole:
return Qt::AlignCenter; switch (index.column()) {
case 3:
case 4:
return Qt::AlignLeft;
default:
return Qt::AlignCenter;
}
} }
return QVariant(); return QVariant();
} }
@ -79,12 +118,20 @@ QVariant FindResultModel::headerData(int section, Qt::Orientation orientation,
return QVariant(); 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<WingHex::FindResult> &FindResultModel::results() { return m_results; }
QList<FindResultModel::FindInfo> &FindResultModel::lastFindData() { QList<FindResultModel::FindInfo> &FindResultModel::findData() {
return m_lastFindData; return m_findData;
} }
QByteArray &FindResultModel::lastFindData() { return m_lastFindData; }
void FindResultModel::beginUpdate() { this->beginResetModel(); } void FindResultModel::beginUpdate() { this->beginResetModel(); }
void FindResultModel::endUpdate() { this->endResetModel(); } void FindResultModel::endUpdate() { this->endResetModel(); }
@ -95,7 +142,7 @@ WingHex::FindResult FindResultModel::resultAt(qsizetype index) const {
void FindResultModel::clear() { void FindResultModel::clear() {
m_results.clear(); m_results.clear();
m_lastFindData.clear(); m_findData.clear();
} }
QList<WingHex::FindResult>::size_type FindResultModel::size() const { QList<WingHex::FindResult>::size_type FindResultModel::size() const {

View File

@ -24,17 +24,21 @@
class FindResultModel : public QAbstractTableModel { class FindResultModel : public QAbstractTableModel {
Q_OBJECT Q_OBJECT
public: public:
struct FindInfo { struct FindInfo {
QString findRange; QByteArray cheader;
QString decoding; QByteArray hbuffer;
QByteArray tbuffer;
QByteArray ctailer;
}; };
public: public:
explicit FindResultModel(QObject *parent = nullptr); explicit FindResultModel(QObject *parent = nullptr);
QList<WingHex::FindResult> &results(); QList<WingHex::FindResult> &results();
QList<FindInfo> &lastFindData(); QList<FindInfo> &findData();
QByteArray &lastFindData();
void beginUpdate(); void beginUpdate();
void endUpdate(); void endUpdate();
@ -51,9 +55,15 @@ public:
virtual QVariant headerData(int section, Qt::Orientation orientation, virtual QVariant headerData(int section, Qt::Orientation orientation,
int role) const override; int role) const override;
QString encoding() const;
void setEncoding(const QString &newEncoding);
private: private:
QList<WingHex::FindResult> m_results; QList<WingHex::FindResult> m_results;
QList<FindInfo> m_lastFindData; QList<FindInfo> m_findData;
QByteArray m_lastFindData;
QString m_encoding;
}; };
#endif // FINDRESULTMODEL_H #endif // FINDRESULTMODEL_H

View File

@ -401,30 +401,32 @@ public:
typedef ClickedCallBack DoubleClickedCallBack; typedef ClickedCallBack DoubleClickedCallBack;
signals: signals:
bool updateText(const QString &data); bool updateText(const QString &data, const QString &title = {});
bool updateTextList(const QStringList &data, ClickedCallBack clicked = {}, bool updateTextList(const QStringList &data, const QString &title = {},
ClickedCallBack clicked = {},
DoubleClickedCallBack dblClicked = {}); DoubleClickedCallBack dblClicked = {});
Q_REQUIRED_RESULT bool Q_REQUIRED_RESULT bool
updateTextTree(const QString &json, ClickedCallBack clicked = {}, updateTextTree(const QString &json, const QString &title = {},
ClickedCallBack clicked = {},
DoubleClickedCallBack dblClicked = {}); DoubleClickedCallBack dblClicked = {});
Q_REQUIRED_RESULT bool Q_REQUIRED_RESULT bool
updateTextTable(const QString &json, const QStringList &headers, updateTextTable(const QString &json, const QStringList &headers,
const QStringList &headerNames = {}, const QStringList &headerNames = {},
ClickedCallBack clicked = {}, const QString &title = {}, ClickedCallBack clicked = {},
DoubleClickedCallBack dblClicked = {}); DoubleClickedCallBack dblClicked = {});
// API for Qt Plugin Only // API for Qt Plugin Only
Q_REQUIRED_RESULT bool Q_REQUIRED_RESULT bool
updateTextListByModel(QAbstractItemModel *model, updateTextListByModel(QAbstractItemModel *model, const QString &title = {},
ClickedCallBack clicked = {}, ClickedCallBack clicked = {},
DoubleClickedCallBack dblClicked = {}); DoubleClickedCallBack dblClicked = {});
Q_REQUIRED_RESULT bool Q_REQUIRED_RESULT bool
updateTextTableByModel(QAbstractItemModel *model, updateTextTableByModel(QAbstractItemModel *model, const QString &title = {},
ClickedCallBack clicked = {}, ClickedCallBack clicked = {},
DoubleClickedCallBack dblClicked = {}); DoubleClickedCallBack dblClicked = {});
Q_REQUIRED_RESULT bool Q_REQUIRED_RESULT bool
updateTextTreeByModel(QAbstractItemModel *model, updateTextTreeByModel(QAbstractItemModel *model, const QString &title = {},
ClickedCallBack clicked = {}, ClickedCallBack clicked = {},
DoubleClickedCallBack dblClicked = {}); DoubleClickedCallBack dblClicked = {});
}; };
@ -494,7 +496,13 @@ signals:
struct WingDependency { struct WingDependency {
QString puid; QString puid;
uint version; uint version;
QString md5; // optional, but recommend QByteArray md5; // optional, but recommend
};
struct SenderInfo {
QString plgcls;
QString puid;
QVariant meta;
}; };
#ifdef WING_SERVICE #ifdef WING_SERVICE
@ -602,8 +610,9 @@ public:
return {}; return {};
} }
// QHash< obj-names, decl-members > // QHash< enum , members >
virtual QHash<QString, QStringList> registeredScriptObjs() const { virtual QHash<QString, QList<QPair<QString, int>>>
registeredScriptEnums() const {
return {}; return {};
} }
@ -655,8 +664,7 @@ signals:
QGenericArgument val5 = QGenericArgument(), QGenericArgument val5 = QGenericArgument(),
QGenericArgument val6 = QGenericArgument(), QGenericArgument val6 = QGenericArgument(),
QGenericArgument val7 = QGenericArgument(), QGenericArgument val7 = QGenericArgument(),
QGenericArgument val8 = QGenericArgument(), QGenericArgument val8 = QGenericArgument());
QGenericArgument val9 = QGenericArgument());
public: public:
inline bool invokeService(const QString &puid, const char *member, inline bool invokeService(const QString &puid, const char *member,
@ -669,11 +677,10 @@ public:
QGenericArgument val5 = QGenericArgument(), QGenericArgument val5 = QGenericArgument(),
QGenericArgument val6 = QGenericArgument(), QGenericArgument val6 = QGenericArgument(),
QGenericArgument val7 = QGenericArgument(), QGenericArgument val7 = QGenericArgument(),
QGenericArgument val8 = QGenericArgument(), QGenericArgument val8 = QGenericArgument()) {
QGenericArgument val9 = QGenericArgument()) {
return emit invokeService(puid, member, Qt::AutoConnection, ret, val0, return emit invokeService(puid, member, Qt::AutoConnection, ret, val0,
val1, val2, val3, val4, val5, val6, val7, val1, val2, val3, val4, val5, val6, val7,
val8, val9); val8);
} }
inline bool invokeService(const QString &puid, const char *member, inline bool invokeService(const QString &puid, const char *member,
@ -685,11 +692,10 @@ public:
QGenericArgument val5 = QGenericArgument(), QGenericArgument val5 = QGenericArgument(),
QGenericArgument val6 = QGenericArgument(), QGenericArgument val6 = QGenericArgument(),
QGenericArgument val7 = QGenericArgument(), QGenericArgument val7 = QGenericArgument(),
QGenericArgument val8 = QGenericArgument(), QGenericArgument val8 = QGenericArgument()) {
QGenericArgument val9 = QGenericArgument()) {
return emit invokeService(puid, member, type, QGenericReturnArgument(), return emit invokeService(puid, member, type, QGenericReturnArgument(),
val0, val1, val2, val3, val4, val5, val6, val0, val1, val2, val3, val4, val5, val6,
val7, val8, val9); val7, val8);
} }
inline bool invokeService(const QString &puid, const char *member, inline bool invokeService(const QString &puid, const char *member,
@ -701,11 +707,10 @@ public:
QGenericArgument val5 = QGenericArgument(), QGenericArgument val5 = QGenericArgument(),
QGenericArgument val6 = QGenericArgument(), QGenericArgument val6 = QGenericArgument(),
QGenericArgument val7 = QGenericArgument(), QGenericArgument val7 = QGenericArgument(),
QGenericArgument val8 = QGenericArgument(), QGenericArgument val8 = QGenericArgument()) {
QGenericArgument val9 = QGenericArgument()) {
return emit invokeService(puid, member, Qt::AutoConnection, return emit invokeService(puid, member, Qt::AutoConnection,
QGenericReturnArgument(), val0, val1, val2, QGenericReturnArgument(), val0, val1, val2,
val3, val4, val5, val6, val7, val8, val9); val3, val4, val5, val6, val7, val8);
} }
public: public:
@ -720,6 +725,7 @@ public:
} // namespace WingHex } // namespace WingHex
Q_DECLARE_METATYPE(WingHex::SenderInfo)
Q_DECLARE_INTERFACE(WingHex::IWingPlugin, "com.wingsummer.iwingplugin") Q_DECLARE_INTERFACE(WingHex::IWingPlugin, "com.wingsummer.iwingplugin")
#endif // IWINGPLUGIN_H #endif // IWINGPLUGIN_H

View File

@ -68,15 +68,14 @@ void PluginSystem::loadPlugin(const QFileInfo &fileinfo, const QDir &setdir) {
Q_ASSERT(_win); Q_ASSERT(_win);
if (fileinfo.exists()) { if (fileinfo.exists()) {
QPluginLoader loader(fileinfo.absoluteFilePath(), this); auto fileName = fileinfo.absoluteFilePath();
QPluginLoader loader(fileName, this);
Logger::info(tr("LoadingPlugin") + fileinfo.fileName()); Logger::info(tr("LoadingPlugin") + fileinfo.fileName());
auto p = qobject_cast<IWingPlugin *>(loader.instance()); auto p = qobject_cast<IWingPlugin *>(loader.instance());
if (Q_UNLIKELY(p == nullptr)) { if (Q_UNLIKELY(p == nullptr)) {
Logger::critical(loader.errorString()); Logger::critical(loader.errorString());
} else { } else {
if (!loadPlugin(p, setdir)) { loadPlugin(p, fileName, setdir);
loader.unload();
}
} }
Logger::_log(""); Logger::_log("");
} }
@ -299,6 +298,17 @@ void PluginSystem::registerFns(IWingPlugin *plg) {
_angelplg->registerScriptFns(plg->metaObject()->className(), rfns); _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) { void PluginSystem::registerEvents(IWingPlugin *plg) {
Q_ASSERT(plg); Q_ASSERT(plg);
auto evs = plg->registeredEvents(); auto evs = plg->registeredEvents();
@ -445,15 +455,35 @@ QString PluginSystem::getScriptFnSig(const QString &fnName,
QString PluginSystem::getPUID(IWingPlugin *p) { QString PluginSystem::getPUID(IWingPlugin *p) {
if (p) { if (p) {
constexpr auto puid_limit = 36; // same as uuid length, so enough
auto prop = p->property("puid").toString().trimmed(); auto prop = p->property("puid").toString().trimmed();
if (prop.length() > puid_limit) {
return {};
}
auto pid = QString(p->metaObject()->className()); auto pid = QString(p->metaObject()->className());
if (pid.length() > puid_limit) {
return {};
}
return prop.isEmpty() ? pid : prop; return prop.isEmpty() ? pid : prop;
} else { } else {
return {}; 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) { const std::optional<QDir> &setdir) {
QTranslator *p_tr = nullptr; QTranslator *p_tr = nullptr;
@ -471,8 +501,25 @@ bool PluginSystem::loadPlugin(IWingPlugin *p,
} }
auto puid = getPUID(p); auto puid = getPUID(p);
if (_loadedpuid.contains(puid)) { if (puid.isEmpty()) {
throw tr("ErrLoadLoadedPlugin"); 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()); emit pluginLoading(p->pluginName());
@ -496,8 +543,14 @@ bool PluginSystem::loadPlugin(IWingPlugin *p,
} }
} }
_loadedplgs.push_back(p); _loadedplgs.append(p);
_loadedpuid << puid;
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("PluginName :") + p->pluginName());
Logger::warning(tr("PluginAuthor :") + p->pluginAuthor()); Logger::warning(tr("PluginAuthor :") + p->pluginAuthor());
@ -665,6 +718,7 @@ bool PluginSystem::loadPlugin(IWingPlugin *p,
} }
registerFns(p); registerFns(p);
registerEnums(p);
registerEvents(p); registerEvents(p);
connectInterface(p); connectInterface(p);
@ -674,9 +728,7 @@ bool PluginSystem::loadPlugin(IWingPlugin *p,
if (p_tr) { if (p_tr) {
p_tr->deleteLater(); p_tr->deleteLater();
} }
return false;
} }
return true;
} }
void PluginSystem::connectInterface(IWingPlugin *plg) { void PluginSystem::connectInterface(IWingPlugin *plg) {
@ -738,22 +790,22 @@ void PluginSystem::connectBaseInterface(IWingPlugin *plg) {
QGenericReturnArgument, QGenericArgument, QGenericArgument, QGenericReturnArgument, QGenericArgument, QGenericArgument,
QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument,
QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument,
QGenericArgument,
QGenericArgument>::of(&IWingPlugin::invokeService), QGenericArgument>::of(&IWingPlugin::invokeService),
this, this,
[=](const QString &puid, const char *method, Qt::ConnectionType type, [=](const QString &puid, const char *method, Qt::ConnectionType type,
QGenericReturnArgument ret, QGenericArgument val0, QGenericReturnArgument ret, QGenericArgument val0,
QGenericArgument val1, QGenericArgument val2, QGenericArgument val3, QGenericArgument val1, QGenericArgument val2, QGenericArgument val3,
QGenericArgument val4, QGenericArgument val5, QGenericArgument val6, QGenericArgument val4, QGenericArgument val5, QGenericArgument val6,
QGenericArgument val7, QGenericArgument val8, QGenericArgument val7, QGenericArgument val8) -> bool {
QGenericArgument val9) -> bool {
auto r = std::find_if( auto r = std::find_if(
_loadedplgs.begin(), _loadedplgs.end(), _loadedplgs.begin(), _loadedplgs.end(),
[=](IWingPlugin *plg) { return getPUID(plg) == puid; }); [=](IWingPlugin *plg) { return getPUID(plg) == puid; });
if (r == _loadedplgs.end()) { if (r == _loadedplgs.end()) {
return false; return false;
} }
auto meta = (*r)->metaObject();
auto obj = *r;
auto meta = obj->metaObject();
// filter the evil call and report to log // filter the evil call and report to log
QVarLengthArray<char, 512> sig; QVarLengthArray<char, 512> sig;
@ -762,10 +814,13 @@ void PluginSystem::connectBaseInterface(IWingPlugin *plg) {
return false; return false;
sig.append(method, len); sig.append(method, len);
sig.append('('); sig.append('(');
const char *typeNames[] = {ret.name(), val0.name(), val1.name(),
val2.name(), val3.name(), val4.name(), auto sname = QMetaType::fromType<WingHex::SenderInfo>().name();
val5.name(), val6.name(), val7.name(),
val8.name(), val9.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; size_t paramCount;
constexpr auto maxParamCount = constexpr auto maxParamCount =
sizeof(typeNames) / sizeof(const char *); sizeof(typeNames) / sizeof(const char *);
@ -803,10 +858,26 @@ void PluginSystem::connectBaseInterface(IWingPlugin *plg) {
return false; return false;
} }
auto obj = *r; meta = plg->metaObject();
obj->setProperty("__LAST_CALLER__", plg->metaObject()->className()); SenderInfo info;
return m.invoke(obj, type, ret, val0, val1, val2, val3, val4, val5, info.plgcls = meta->className();
val6, val7, val8, val9); 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; auto visual = &plg->visual;
connect(visual, &WingPlugin::DataVisual::updateText, _win, 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); _win->m_infotxt->setText(txt);
return true; return true;
}); });
connect( connect(
visual, &WingPlugin::DataVisual::updateTextList, _win, visual, &WingPlugin::DataVisual::updateTextList, _win,
[=](const QStringList &data, [=](const QStringList &data, const QString &title,
WingHex::WingPlugin::DataVisual::ClickedCallBack clicked, WingHex::WingPlugin::DataVisual::ClickedCallBack clicked,
WingHex::WingPlugin::DataVisual::DoubleClickedCallBack dblClicked) WingHex::WingPlugin::DataVisual::DoubleClickedCallBack dblClicked)
-> bool { -> bool {
@ -2166,6 +2238,7 @@ void PluginSystem::connectUIInterface(IWingPlugin *plg) {
if (oldmodel) { if (oldmodel) {
oldmodel->deleteLater(); oldmodel->deleteLater();
} }
_win->m_infolist->setProperty("__TITLE__", title);
auto model = new QStringListModel(data); auto model = new QStringListModel(data);
_win->m_infolist->setModel(model); _win->m_infolist->setModel(model);
_win->m_infoclickfn = clicked; _win->m_infoclickfn = clicked;
@ -2174,7 +2247,7 @@ void PluginSystem::connectUIInterface(IWingPlugin *plg) {
}); });
connect( connect(
visual, &WingPlugin::DataVisual::updateTextListByModel, _win, visual, &WingPlugin::DataVisual::updateTextListByModel, _win,
[=](QAbstractItemModel *model, [=](QAbstractItemModel *model, const QString &title,
WingHex::WingPlugin::DataVisual::ClickedCallBack clicked, WingHex::WingPlugin::DataVisual::ClickedCallBack clicked,
WingHex::WingPlugin::DataVisual::DoubleClickedCallBack dblClicked) WingHex::WingPlugin::DataVisual::DoubleClickedCallBack dblClicked)
-> bool { -> bool {
@ -2183,6 +2256,7 @@ void PluginSystem::connectUIInterface(IWingPlugin *plg) {
if (oldmodel) { if (oldmodel) {
oldmodel->deleteLater(); oldmodel->deleteLater();
} }
_win->m_infolist->setProperty("__TITLE__", title);
_win->m_infolist->setModel(model); _win->m_infolist->setModel(model);
_win->m_infoclickfn = clicked; _win->m_infoclickfn = clicked;
_win->m_infodblclickfn = dblClicked; _win->m_infodblclickfn = dblClicked;
@ -2192,7 +2266,7 @@ void PluginSystem::connectUIInterface(IWingPlugin *plg) {
}); });
connect( connect(
visual, &WingPlugin::DataVisual::updateTextTree, _win, visual, &WingPlugin::DataVisual::updateTextTree, _win,
[=](const QString &json, [=](const QString &json, const QString &title,
WingHex::WingPlugin::DataVisual::ClickedCallBack clicked, WingHex::WingPlugin::DataVisual::ClickedCallBack clicked,
WingHex::WingPlugin::DataVisual::DoubleClickedCallBack dblClicked) WingHex::WingPlugin::DataVisual::DoubleClickedCallBack dblClicked)
-> bool { -> bool {
@ -2200,6 +2274,7 @@ void PluginSystem::connectUIInterface(IWingPlugin *plg) {
if (oldmodel) { if (oldmodel) {
oldmodel->deleteLater(); oldmodel->deleteLater();
} }
_win->m_infotree->setProperty("__TITLE__", title);
auto model = new QJsonModel; auto model = new QJsonModel;
if (model->loadJson(json.toUtf8())) { if (model->loadJson(json.toUtf8())) {
_win->m_infotree->setModel(model); _win->m_infotree->setModel(model);
@ -2211,7 +2286,7 @@ void PluginSystem::connectUIInterface(IWingPlugin *plg) {
}); });
connect( connect(
visual, &WingPlugin::DataVisual::updateTextTreeByModel, _win, visual, &WingPlugin::DataVisual::updateTextTreeByModel, _win,
[=](QAbstractItemModel *model, [=](QAbstractItemModel *model, const QString &title,
WingHex::WingPlugin::DataVisual::ClickedCallBack clicked, WingHex::WingPlugin::DataVisual::ClickedCallBack clicked,
WingHex::WingPlugin::DataVisual::DoubleClickedCallBack dblClicked) WingHex::WingPlugin::DataVisual::DoubleClickedCallBack dblClicked)
-> bool { -> bool {
@ -2220,6 +2295,7 @@ void PluginSystem::connectUIInterface(IWingPlugin *plg) {
if (oldmodel) { if (oldmodel) {
oldmodel->deleteLater(); oldmodel->deleteLater();
} }
_win->m_infotree->setProperty("__TITLE__", title);
_win->m_infotree->setModel(model); _win->m_infotree->setModel(model);
_win->m_infotreeclickfn = clicked; _win->m_infotreeclickfn = clicked;
_win->m_infotreedblclickfn = dblClicked; _win->m_infotreedblclickfn = dblClicked;
@ -2230,7 +2306,7 @@ void PluginSystem::connectUIInterface(IWingPlugin *plg) {
connect( connect(
visual, &WingPlugin::DataVisual::updateTextTable, _win, visual, &WingPlugin::DataVisual::updateTextTable, _win,
[=](const QString &json, const QStringList &headers, [=](const QString &json, const QStringList &headers,
const QStringList &headerNames, const QStringList &headerNames, const QString &title,
WingHex::WingPlugin::DataVisual::ClickedCallBack clicked, WingHex::WingPlugin::DataVisual::ClickedCallBack clicked,
WingHex::WingPlugin::DataVisual::DoubleClickedCallBack dblClicked) WingHex::WingPlugin::DataVisual::DoubleClickedCallBack dblClicked)
-> bool { -> bool {
@ -2257,7 +2333,7 @@ void PluginSystem::connectUIInterface(IWingPlugin *plg) {
header.append(heading); header.append(heading);
} }
} }
_win->m_infotable->setProperty("__TITLE__", title);
auto model = new QJsonTableModel(header); auto model = new QJsonTableModel(header);
model->setJson(QJsonDocument::fromJson(json.toUtf8())); model->setJson(QJsonDocument::fromJson(json.toUtf8()));
_win->m_infotable->setModel(model); _win->m_infotable->setModel(model);
@ -2267,7 +2343,7 @@ void PluginSystem::connectUIInterface(IWingPlugin *plg) {
}); });
connect( connect(
visual, &WingPlugin::DataVisual::updateTextTableByModel, _win, visual, &WingPlugin::DataVisual::updateTextTableByModel, _win,
[=](QAbstractItemModel *model, [=](QAbstractItemModel *model, const QString &title,
WingHex::WingPlugin::DataVisual::ClickedCallBack clicked, WingHex::WingPlugin::DataVisual::ClickedCallBack clicked,
WingHex::WingPlugin::DataVisual::DoubleClickedCallBack dblClicked) WingHex::WingPlugin::DataVisual::DoubleClickedCallBack dblClicked)
-> bool { -> bool {
@ -2276,6 +2352,7 @@ void PluginSystem::connectUIInterface(IWingPlugin *plg) {
if (oldmodel) { if (oldmodel) {
oldmodel->deleteLater(); oldmodel->deleteLater();
} }
_win->m_infotable->setProperty("__TITLE__", title);
_win->m_infotable->setModel(model); _win->m_infotable->setModel(model);
_win->m_infotableclickfn = clicked; _win->m_infotableclickfn = clicked;
_win->m_infotabledblclickfn = dblClicked; _win->m_infotabledblclickfn = dblClicked;
@ -2313,9 +2390,7 @@ void PluginSystem::LoadPlugin() {
if (set.scriptEnabled()) { if (set.scriptEnabled()) {
_angelplg = new WingAngelAPI; _angelplg = new WingAngelAPI;
auto ret = loadPlugin(_angelplg, std::nullopt); loadPlugin(_angelplg, {}, std::nullopt);
Q_ASSERT(ret);
Q_UNUSED(ret);
} }
bool ok; bool ok;
@ -2370,6 +2445,33 @@ void PluginSystem::LoadPlugin() {
loadPlugin(item, udir); 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")); Logger::info(tr("PluginLoadingFinished"));
} }

View File

@ -126,6 +126,7 @@ public:
private: private:
void registerFns(IWingPlugin *plg); void registerFns(IWingPlugin *plg);
void registerEnums(IWingPlugin *plg);
void registerEvents(IWingPlugin *plg); void registerEvents(IWingPlugin *plg);
QString type2AngelScriptString(IWingPlugin::MetaType type, bool isArg); QString type2AngelScriptString(IWingPlugin::MetaType type, bool isArg);
@ -135,8 +136,11 @@ private:
QString getPUID(IWingPlugin *p); QString getPUID(IWingPlugin *p);
bool isPluginLoaded(const WingDependency &d);
private: 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 connectInterface(IWingPlugin *plg);
void connectLoadingInterface(IWingPlugin *plg); void connectLoadingInterface(IWingPlugin *plg);
@ -230,8 +234,9 @@ private:
private: private:
MainWindow *_win = nullptr; MainWindow *_win = nullptr;
QStringList _loadedpuid; QList<WingDependency> _loadedplginfo;
QList<IWingPlugin *> _loadedplgs; QList<IWingPlugin *> _loadedplgs;
QList<QPair<IWingPlugin *, QString>> _lazyplgs;
QMap<IWingPlugin::RegisteredEvent, QList<IWingPlugin *>> _evplgs; QMap<IWingPlugin::RegisteredEvent, QList<IWingPlugin *>> _evplgs;

View File

@ -50,6 +50,9 @@
#define PROEXT ".wingpro" #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) { Q_DECL_UNUSED static inline QString NAMEICONRES(const QString &name) {
return ":/com.wingsummer.winghex/images/" + name + ".png"; return ":/com.wingsummer.winghex/images/" + name + ".png";
} }
@ -156,6 +159,10 @@ public:
} }
static QByteArray getMd5(QString filename) { static QByteArray getMd5(QString filename) {
if (filename.isEmpty()) {
return {};
}
QFile sourceFile(filename); QFile sourceFile(filename);
if (sourceFile.open(QIODevice::ReadOnly)) { if (sourceFile.open(QIODevice::ReadOnly)) {
QCryptographicHash hash(QCryptographicHash::Md5); QCryptographicHash hash(QCryptographicHash::Md5);
@ -163,7 +170,7 @@ public:
return hash.result(); return hash.result();
} }
} }
return QByteArray(); return {};
} }
static bool checkIsLittleEndian() { static bool checkIsLittleEndian() {