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:
void documentChanged(QHexDocument *doc);
void cursorLocationChanged();
void cursorSelectionChanged(); // TODO
void cursorSelectionChanged();
void canUndoChanged(bool canUndo);
void canRedoChanged(bool canRedo);
void documentSaved(bool saved);

View File

@ -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>

View File

@ -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

View File

@ -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);
}

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 <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();
}

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

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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; }

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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 {

View File

@ -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

View File

@ -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

View File

@ -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"));
}

View File

@ -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;

View File

@ -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() {