feat: 优化选区功能;完成插件系统升级;修复查找编码应用无效问题;
This commit is contained in:
parent
bd5ddfba9a
commit
3e21be134c
|
@ -93,6 +93,7 @@ bool QHexCursor::hasInternalSelection() const { return !m_sels.isEmpty(); }
|
|||
void QHexCursor::clearPreviewSelection() {
|
||||
m_selection = m_position;
|
||||
m_preMode = SelectionNormal;
|
||||
emit selectionChanged();
|
||||
}
|
||||
|
||||
void QHexCursor::clearSelection() { m_sels.clear(); }
|
||||
|
@ -156,7 +157,6 @@ void QHexCursor::select(qsizetype line, int column, int nibbleindex,
|
|||
}
|
||||
}
|
||||
|
||||
emit positionChanged();
|
||||
emit selectionChanged();
|
||||
}
|
||||
|
||||
|
@ -306,4 +306,6 @@ void QHexCursor::mergePreviewSelection() {
|
|||
break;
|
||||
}
|
||||
clearPreviewSelection();
|
||||
|
||||
emit selectionChanged();
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ struct QHexPosition {
|
|||
return this->offset() >= rhs.offset();
|
||||
}
|
||||
};
|
||||
Q_DECLARE_METATYPE(QHexPosition)
|
||||
|
||||
struct QHexSelection {
|
||||
QHexPosition start;
|
||||
|
|
|
@ -96,12 +96,17 @@ bool QHexDocument::metaCommentVisible() { return m_metacomment; }
|
|||
void QHexDocument::insertBookMarkAdjust(qsizetype offset, qsizetype length) {
|
||||
QMap<qsizetype, QString> bms;
|
||||
|
||||
if (_bookmarks.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
auto rmbegin = _bookmarks.lowerBound(offset);
|
||||
#else
|
||||
auto rmbegin = std::as_const(_bookmarks).lowerBound(offset);
|
||||
#endif
|
||||
auto addbegin = _bookmarks.upperBound(offset);
|
||||
|
||||
for (auto p = addbegin; p != _bookmarks.end(); ++p) {
|
||||
bms.insert(p.key() + length, p.value());
|
||||
}
|
||||
|
@ -120,6 +125,10 @@ void QHexDocument::insertBookMarkAdjust(qsizetype offset, qsizetype length) {
|
|||
void QHexDocument::removeBookMarkAdjust(qsizetype offset, qsizetype length) {
|
||||
QMap<qsizetype, QString> bms;
|
||||
|
||||
if (_bookmarks.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
auto rmbegin = _bookmarks.lowerBound(offset);
|
||||
#else
|
||||
|
|
|
@ -113,8 +113,10 @@ void QHexView::establishSignal(QHexDocument *doc) {
|
|||
|
||||
connect(m_cursor, &QHexCursor::positionChanged, this,
|
||||
&QHexView::moveToSelection);
|
||||
connect(m_cursor, &QHexCursor::selectionChanged, this,
|
||||
[this]() { this->viewport()->update(); });
|
||||
connect(m_cursor, &QHexCursor::selectionChanged, this, [this]() {
|
||||
this->viewport()->update();
|
||||
emit cursorSelectionChanged();
|
||||
});
|
||||
connect(m_cursor, &QHexCursor::insertionModeChanged, this,
|
||||
&QHexView::renderCurrentLine);
|
||||
connect(doc, &QHexDocument::canUndoChanged, this,
|
||||
|
|
|
@ -128,6 +128,7 @@ private:
|
|||
signals:
|
||||
void documentChanged(QHexDocument *doc);
|
||||
void cursorLocationChanged();
|
||||
void cursorSelectionChanged(); // TODO
|
||||
void canUndoChanged(bool canUndo);
|
||||
void canRedoChanged(bool canRedo);
|
||||
void documentSaved(bool saved);
|
||||
|
|
|
@ -188,7 +188,9 @@ set(CONTROL_SRC
|
|||
src/control/codeedit.h
|
||||
src/control/codeedit.cpp
|
||||
src/control/asobjtreewidget.h
|
||||
src/control/asobjtreewidget.cpp)
|
||||
src/control/asobjtreewidget.cpp
|
||||
src/control/qtlonglongspinbox.cpp
|
||||
src/control/qtlonglongspinbox.h)
|
||||
|
||||
set(CLASS_SRC
|
||||
src/class/logger.cpp
|
||||
|
@ -252,7 +254,9 @@ set(CLASS_SRC
|
|||
src/class/layoutmanager.h
|
||||
src/class/layoutmanager.cpp
|
||||
src/class/wingupdater.h
|
||||
src/class/wingupdater.cpp)
|
||||
src/class/wingupdater.cpp
|
||||
src/class/richtextitemdelegate.h
|
||||
src/class/richtextitemdelegate.cpp)
|
||||
|
||||
if(WINGHEX_USE_FRAMELESS)
|
||||
set(WIDGET_FRAME_SRC
|
||||
|
|
|
@ -316,30 +316,30 @@
|
|||
<context>
|
||||
<name>TestPlugin</name>
|
||||
<message>
|
||||
<location filename="../testplugin.cpp" line="83"/>
|
||||
<location filename="../testplugin.cpp" line="84"/>
|
||||
<source>Test</source>
|
||||
<translation>测试</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../testplugin.cpp" line="95"/>
|
||||
<location filename="../testplugin.cpp" line="104"/>
|
||||
<location filename="../testplugin.cpp" line="109"/>
|
||||
<location filename="../testplugin.cpp" line="190"/>
|
||||
<location filename="../testplugin.cpp" line="96"/>
|
||||
<location filename="../testplugin.cpp" line="105"/>
|
||||
<location filename="../testplugin.cpp" line="110"/>
|
||||
<location filename="../testplugin.cpp" line="191"/>
|
||||
<source>TestPlugin</source>
|
||||
<translation>测试插件</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../testplugin.cpp" line="113"/>
|
||||
<location filename="../testplugin.cpp" line="114"/>
|
||||
<source>Button - </source>
|
||||
<translation>按钮 - </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../testplugin.cpp" line="117"/>
|
||||
<location filename="../testplugin.cpp" line="118"/>
|
||||
<source>Click</source>
|
||||
<translation>点击</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../testplugin.cpp" line="197"/>
|
||||
<location filename="../testplugin.cpp" line="198"/>
|
||||
<source>A Test Plugin for WingHexExplorer2.</source>
|
||||
<translation>一个用来测试羽云十六进制编辑器2的插件</translation>
|
||||
</message>
|
||||
|
|
|
@ -245,6 +245,18 @@ void TestPlugin::test_b(const QString &a) {
|
|||
}
|
||||
|
||||
QHash<QString, WingHex::IWingPlugin::ScriptFnInfo>
|
||||
TestPlugin::registeredScriptFn() {
|
||||
TestPlugin::registeredScriptFns() const {
|
||||
return _scriptInfo;
|
||||
}
|
||||
|
||||
WingHex::IWingPlugin::RegisteredEvents TestPlugin::registeredEvents() const {
|
||||
return RegisteredEvent::AppReady;
|
||||
}
|
||||
|
||||
void TestPlugin::eventReady() {
|
||||
bool ret;
|
||||
emit invokeService(
|
||||
QStringLiteral("WingAngelAPI"), "execCode", Qt::AutoConnection,
|
||||
WINGAPI_RETURN_ARG(bool, ret),
|
||||
WINGAPI_ARG(QString, R"(print("Hello, this is TestPlugin!");)"));
|
||||
}
|
||||
|
|
|
@ -66,7 +66,10 @@ public:
|
|||
virtual QList<WingHex::PluginPage *> registeredPages() const override;
|
||||
virtual QList<WingHex::WingEditorViewWidget *>
|
||||
registeredEditorViewWidgets() const override;
|
||||
virtual QHash<QString, ScriptFnInfo> registeredScriptFn() override;
|
||||
virtual QHash<QString, ScriptFnInfo> registeredScriptFns() const override;
|
||||
|
||||
virtual RegisteredEvents registeredEvents() const override;
|
||||
virtual void eventReady() override;
|
||||
|
||||
private:
|
||||
QString getPuid() const;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,54 @@
|
|||
#include "richtextitemdelegate.h"
|
||||
|
||||
#include <QAbstractTextDocumentLayout>
|
||||
#include <QApplication>
|
||||
#include <QPainter>
|
||||
#include <QTextDocument>
|
||||
|
||||
RichTextItemDelegate::RichTextItemDelegate(QObject *parent)
|
||||
: QStyledItemDelegate(parent) {}
|
||||
|
||||
void RichTextItemDelegate::paint(QPainter *painter,
|
||||
const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const {
|
||||
auto options = option;
|
||||
initStyleOption(&options, index);
|
||||
|
||||
painter->save();
|
||||
|
||||
QTextDocument doc;
|
||||
doc.setHtml(options.text);
|
||||
|
||||
options.text.clear();
|
||||
options.widget->style()->drawControl(QStyle::CE_ItemViewItem, &options,
|
||||
painter);
|
||||
|
||||
// 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());
|
||||
|
||||
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);
|
||||
|
||||
ctx.clip = clip;
|
||||
doc.documentLayout()->draw(painter, ctx);
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
QSize RichTextItemDelegate::sizeHint(const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const {
|
||||
auto options = option;
|
||||
initStyleOption(&options, index);
|
||||
|
||||
QTextDocument doc;
|
||||
doc.setHtml(options.text);
|
||||
doc.setTextWidth(options.rect.width());
|
||||
return QSize(doc.idealWidth(), doc.size().height());
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef RICHTEXTITEMDELEGATE_H
|
||||
#define RICHTEXTITEMDELEGATE_H
|
||||
|
||||
#include <QStyledItemDelegate>
|
||||
|
||||
class RichTextItemDelegate : public QStyledItemDelegate {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit RichTextItemDelegate(QObject *parent = nullptr);
|
||||
|
||||
// QAbstractItemDelegate interface
|
||||
public:
|
||||
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const override;
|
||||
virtual QSize sizeHint(const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const override;
|
||||
};
|
||||
|
||||
#endif // RICHTEXTITEMDELEGATE_H
|
|
@ -23,6 +23,7 @@
|
|||
#include "class/scriptmachine.h"
|
||||
#include "class/wingfiledialog.h"
|
||||
#include "class/winginputdialog.h"
|
||||
#include "control/scriptingconsole.h"
|
||||
#include "define.h"
|
||||
#include "scriptaddon/scriptqdictionary.h"
|
||||
|
||||
|
@ -96,6 +97,8 @@ void WingAngelAPI::registerScriptFns(const QString &ns,
|
|||
}
|
||||
|
||||
void WingAngelAPI::installAPI(ScriptMachine *machine) {
|
||||
Q_ASSERT(machine);
|
||||
|
||||
auto engine = machine->engine();
|
||||
auto stringTypeID = machine->typeInfo(ScriptMachine::tString)->GetTypeId();
|
||||
|
||||
|
@ -566,12 +569,6 @@ void WingAngelAPI::installHexReaderAPI(asIScriptEngine *engine) {
|
|||
engine, std::bind(&WingHex::WingPlugin::Reader::addressBase, reader),
|
||||
QPTR_WRAP("addressBase()"));
|
||||
|
||||
registerAPI<bool(qsizetype, void *, int)>(
|
||||
engine,
|
||||
std::bind(&WingAngelAPI::_HexReader_read, this, std::placeholders::_1,
|
||||
std::placeholders::_2, std::placeholders::_3),
|
||||
"bool read(" QSIZETYPE " offset, ? &out obj)");
|
||||
|
||||
registerAPI<CScriptArray *(qsizetype, qsizetype)>(
|
||||
engine,
|
||||
std::bind(&WingAngelAPI::_HexReader_readBytes, this,
|
||||
|
@ -738,24 +735,6 @@ void WingAngelAPI::installHexControllerAPI(asIScriptEngine *engine) {
|
|||
std::placeholders::_1),
|
||||
"bool setAddressBase(" QPTR " base)");
|
||||
|
||||
registerAPI<bool(qsizetype, void *, int)>(
|
||||
engine,
|
||||
std::bind(&WingAngelAPI::_HexReader_write, this, std::placeholders::_1,
|
||||
std::placeholders::_2, std::placeholders::_3),
|
||||
"bool write(" QSIZETYPE " offset, ? &in obj)");
|
||||
|
||||
registerAPI<bool(qsizetype, void *, int)>(
|
||||
engine,
|
||||
std::bind(&WingAngelAPI::_HexReader_insert, this, std::placeholders::_1,
|
||||
std::placeholders::_2, std::placeholders::_3),
|
||||
"bool insert(" QSIZETYPE " offset, ? &in obj)");
|
||||
|
||||
registerAPI<bool(void *, int)>(engine,
|
||||
std::bind(&WingAngelAPI::_HexReader_append,
|
||||
this, std::placeholders::_1,
|
||||
std::placeholders::_2),
|
||||
"bool append(? &in obj)");
|
||||
|
||||
registerAPI<bool(qsizetype, qint8)>(
|
||||
engine,
|
||||
std::bind(&WingHex::WingPlugin::Controller::writeInt8, ctl,
|
||||
|
@ -1232,329 +1211,6 @@ QByteArray WingAngelAPI::cArray2ByteArray(const CScriptArray &array, int byteID,
|
|||
return buffer;
|
||||
}
|
||||
|
||||
bool WingAngelAPI::read2Ref(qsizetype offset, void *ref, int typeId) {
|
||||
asIScriptContext *ctx = asGetActiveContext();
|
||||
if (ctx) {
|
||||
asIScriptEngine *engine = ctx->GetEngine();
|
||||
|
||||
if (typeId == asTYPEID_VOID)
|
||||
return false;
|
||||
else if (typeId == asTYPEID_BOOL)
|
||||
*reinterpret_cast<bool *>(ref) =
|
||||
(emit reader.readInt8(offset) != 0);
|
||||
else if (typeId == asTYPEID_INT8)
|
||||
*reinterpret_cast<qint8 *>(ref) = emit reader.readInt8(offset);
|
||||
else if (typeId == asTYPEID_INT16)
|
||||
*reinterpret_cast<qint16 *>(ref) = emit reader.readInt16(offset);
|
||||
else if (typeId == asTYPEID_INT32)
|
||||
*reinterpret_cast<qint32 *>(ref) = emit reader.readInt32(offset);
|
||||
else if (typeId == asTYPEID_INT64)
|
||||
*reinterpret_cast<qint64 *>(ref) = emit reader.readInt64(offset);
|
||||
else if (typeId == asTYPEID_UINT8)
|
||||
*reinterpret_cast<quint8 *>(ref) =
|
||||
quint8(emit reader.readInt8(offset));
|
||||
else if (typeId == asTYPEID_UINT16)
|
||||
*reinterpret_cast<quint16 *>(ref) =
|
||||
quint16(emit reader.readInt16(offset));
|
||||
else if (typeId == asTYPEID_UINT32)
|
||||
*reinterpret_cast<quint32 *>(ref) =
|
||||
quint32(emit reader.readInt32(offset));
|
||||
else if (typeId == asTYPEID_UINT64)
|
||||
*reinterpret_cast<quint64 *>(ref) =
|
||||
quint64(emit reader.readInt64(offset));
|
||||
else if (typeId == asTYPEID_FLOAT)
|
||||
*reinterpret_cast<float *>(ref) = emit reader.readFloat(offset);
|
||||
else if (typeId == asTYPEID_DOUBLE)
|
||||
*reinterpret_cast<double *>(ref) = emit reader.readDouble(offset);
|
||||
else if ((typeId & asTYPEID_MASK_OBJECT) == 0) {
|
||||
bool ok = false;
|
||||
// Check if the value matches one of the defined enums
|
||||
if (engine) {
|
||||
asITypeInfo *t = engine->GetTypeInfoById(typeId);
|
||||
for (int n = t->GetEnumValueCount(); n-- > 0;) {
|
||||
int enumVal;
|
||||
t->GetEnumValueByIndex(n, &enumVal);
|
||||
if (enumVal == *(int *)ref) {
|
||||
*reinterpret_cast<int *>(ref) = enumVal;
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
} else if (typeId & asTYPEID_SCRIPTOBJECT) {
|
||||
void *value = ref;
|
||||
|
||||
// Dereference handles, so we can see what it points to
|
||||
if (typeId & asTYPEID_OBJHANDLE)
|
||||
value = *(void **)value;
|
||||
|
||||
asIScriptObject *obj = (asIScriptObject *)value;
|
||||
|
||||
if (obj) {
|
||||
for (asUINT n = 0; n < obj->GetPropertyCount(); n++) {
|
||||
auto id = obj->GetPropertyTypeId(n);
|
||||
auto data = obj->GetAddressOfProperty(n);
|
||||
auto size = getAsTypeSize(id, data);
|
||||
auto ret = read2Ref(offset, data, id);
|
||||
if (!ret) {
|
||||
return false;
|
||||
}
|
||||
if (size > 0) {
|
||||
offset += size;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Dereference handles, so we can see what it points to
|
||||
void *value = ref;
|
||||
|
||||
if (typeId & asTYPEID_OBJHANDLE)
|
||||
value = *(void **)value;
|
||||
|
||||
if (engine) {
|
||||
asITypeInfo *type = engine->GetTypeInfoByName("string");
|
||||
if (value) {
|
||||
// only string supported
|
||||
if (type->GetTypeId() == (typeId & ~asTYPEID_OBJHANDLE)) {
|
||||
*reinterpret_cast<QString *>(value) =
|
||||
emit reader.readString(offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool WingAngelAPI::write2Ref(qsizetype offset, void *ref, int typeId) {
|
||||
asIScriptContext *ctx = asGetActiveContext();
|
||||
if (ctx) {
|
||||
asIScriptEngine *engine = ctx->GetEngine();
|
||||
|
||||
if (typeId == asTYPEID_VOID)
|
||||
return false;
|
||||
else if (typeId == asTYPEID_BOOL)
|
||||
return emit controller.writeInt8(
|
||||
offset, *reinterpret_cast<bool *>(ref) ? 1 : 0);
|
||||
else if (typeId == asTYPEID_INT8 || typeId == asTYPEID_UINT8)
|
||||
return emit controller.writeInt8(offset,
|
||||
*reinterpret_cast<qint8 *>(ref));
|
||||
else if (typeId == asTYPEID_INT16 || typeId == asTYPEID_UINT16)
|
||||
return emit controller.writeInt16(offset,
|
||||
*reinterpret_cast<qint16 *>(ref));
|
||||
else if (typeId == asTYPEID_INT32 || typeId == asTYPEID_UINT32)
|
||||
return emit controller.writeInt32(offset,
|
||||
*reinterpret_cast<qint32 *>(ref));
|
||||
else if (typeId == asTYPEID_INT64 || typeId == asTYPEID_UINT64)
|
||||
return emit controller.writeInt64(offset,
|
||||
*reinterpret_cast<qint64 *>(ref));
|
||||
else if (typeId == asTYPEID_FLOAT)
|
||||
return emit controller.writeFloat(offset,
|
||||
*reinterpret_cast<float *>(ref));
|
||||
else if (typeId == asTYPEID_DOUBLE)
|
||||
return emit controller.writeDouble(
|
||||
offset, *reinterpret_cast<double *>(ref));
|
||||
else if ((typeId & asTYPEID_MASK_OBJECT) == 0)
|
||||
return emit controller.writeInt32(offset,
|
||||
*reinterpret_cast<int *>(ref));
|
||||
else if (typeId & asTYPEID_SCRIPTOBJECT) {
|
||||
// Dereference handles, so we can see what it points to
|
||||
void *value = ref;
|
||||
if (typeId & asTYPEID_OBJHANDLE)
|
||||
value = *(void **)value;
|
||||
|
||||
asIScriptObject *obj = (asIScriptObject *)value;
|
||||
|
||||
if (obj) {
|
||||
for (asUINT n = 0; n < obj->GetPropertyCount(); n++) {
|
||||
auto id = obj->GetPropertyTypeId(n);
|
||||
auto data = obj->GetAddressOfProperty(n);
|
||||
auto size = getAsTypeSize(id, data);
|
||||
auto ret = write2Ref(offset, data, id);
|
||||
if (!ret) {
|
||||
return false;
|
||||
}
|
||||
if (size > 0) {
|
||||
offset += size;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Dereference handles, so we can see what it points to
|
||||
void *value = ref;
|
||||
|
||||
if (typeId & asTYPEID_OBJHANDLE)
|
||||
value = *(void **)value;
|
||||
|
||||
if (engine) {
|
||||
asITypeInfo *type = engine->GetTypeInfoById(typeId);
|
||||
if (value) {
|
||||
// only string supported
|
||||
if (type->GetTypeId() == (typeId & ~asTYPEID_OBJHANDLE)) {
|
||||
return emit controller.writeString(
|
||||
offset, *reinterpret_cast<QString *>(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool WingAngelAPI::insert2Ref(qsizetype offset, void *ref, int typeId) {
|
||||
asIScriptContext *ctx = asGetActiveContext();
|
||||
if (ctx) {
|
||||
asIScriptEngine *engine = ctx->GetEngine();
|
||||
|
||||
if (typeId == asTYPEID_VOID)
|
||||
return false;
|
||||
else if (typeId == asTYPEID_BOOL)
|
||||
return emit controller.insertInt8(
|
||||
offset, *reinterpret_cast<bool *>(ref) ? 1 : 0);
|
||||
else if (typeId == asTYPEID_INT8 || typeId == asTYPEID_UINT8)
|
||||
return emit controller.insertInt8(offset,
|
||||
*reinterpret_cast<qint8 *>(ref));
|
||||
else if (typeId == asTYPEID_INT16 || typeId == asTYPEID_UINT16)
|
||||
return emit controller.insertInt16(
|
||||
offset, *reinterpret_cast<qint16 *>(ref));
|
||||
else if (typeId == asTYPEID_INT32 || typeId == asTYPEID_UINT32)
|
||||
return emit controller.insertInt32(
|
||||
offset, *reinterpret_cast<qint32 *>(ref));
|
||||
else if (typeId == asTYPEID_INT64 || typeId == asTYPEID_UINT64)
|
||||
return emit controller.insertInt64(
|
||||
offset, *reinterpret_cast<qint64 *>(ref));
|
||||
else if (typeId == asTYPEID_FLOAT)
|
||||
return emit controller.insertFloat(offset,
|
||||
*reinterpret_cast<float *>(ref));
|
||||
else if (typeId == asTYPEID_DOUBLE)
|
||||
return emit controller.insertDouble(
|
||||
offset, *reinterpret_cast<double *>(ref));
|
||||
else if ((typeId & asTYPEID_MASK_OBJECT) == 0)
|
||||
return emit controller.insertInt32(offset,
|
||||
*reinterpret_cast<int *>(ref));
|
||||
else if (typeId & asTYPEID_SCRIPTOBJECT) {
|
||||
// Dereference handles, so we can see what it points to
|
||||
void *value = ref;
|
||||
if (typeId & asTYPEID_OBJHANDLE)
|
||||
value = *(void **)value;
|
||||
|
||||
asIScriptObject *obj = (asIScriptObject *)value;
|
||||
|
||||
if (obj) {
|
||||
for (asUINT n = 0; n < obj->GetPropertyCount(); n++) {
|
||||
auto id = obj->GetPropertyTypeId(n);
|
||||
auto data = obj->GetAddressOfProperty(n);
|
||||
auto size = getAsTypeSize(id, data);
|
||||
auto ret = insert2Ref(offset, data, id);
|
||||
if (!ret) {
|
||||
return false;
|
||||
}
|
||||
if (size > 0) {
|
||||
offset += size;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Dereference handles, so we can see what it points to
|
||||
void *value = ref;
|
||||
|
||||
if (typeId & asTYPEID_OBJHANDLE)
|
||||
value = *(void **)value;
|
||||
|
||||
if (engine) {
|
||||
asITypeInfo *type = engine->GetTypeInfoById(typeId);
|
||||
if (value) {
|
||||
// TODO support other type, now only string
|
||||
if (type->GetTypeId() == (typeId & ~asTYPEID_OBJHANDLE)) {
|
||||
return emit controller.insertString(
|
||||
offset, *reinterpret_cast<QString *>(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool WingAngelAPI::append2Ref(void *ref, int typeId) {
|
||||
asIScriptContext *ctx = asGetActiveContext();
|
||||
if (ctx) {
|
||||
asIScriptEngine *engine = ctx->GetEngine();
|
||||
|
||||
if (typeId == asTYPEID_VOID)
|
||||
return false;
|
||||
else if (typeId == asTYPEID_BOOL)
|
||||
return emit controller.appendInt8(
|
||||
*reinterpret_cast<bool *>(ref) ? 1 : 0);
|
||||
else if (typeId == asTYPEID_INT8 || typeId == asTYPEID_UINT8)
|
||||
return emit controller.appendInt8(*reinterpret_cast<qint8 *>(ref));
|
||||
else if (typeId == asTYPEID_INT16 || typeId == asTYPEID_UINT16)
|
||||
return emit controller.appendInt16(
|
||||
*reinterpret_cast<qint16 *>(ref));
|
||||
else if (typeId == asTYPEID_INT32 || typeId == asTYPEID_UINT32)
|
||||
return emit controller.appendInt32(
|
||||
*reinterpret_cast<qint32 *>(ref));
|
||||
else if (typeId == asTYPEID_INT64 || typeId == asTYPEID_UINT64)
|
||||
return emit controller.appendInt64(
|
||||
*reinterpret_cast<qint64 *>(ref));
|
||||
else if (typeId == asTYPEID_FLOAT)
|
||||
return emit controller.appendFloat(*reinterpret_cast<float *>(ref));
|
||||
else if (typeId == asTYPEID_DOUBLE)
|
||||
return emit controller.appendDouble(
|
||||
*reinterpret_cast<double *>(ref));
|
||||
else if ((typeId & asTYPEID_MASK_OBJECT) == 0)
|
||||
return emit controller.appendInt32(*reinterpret_cast<int *>(ref));
|
||||
else if (typeId & asTYPEID_SCRIPTOBJECT) {
|
||||
// Dereference handles, so we can see what it points to
|
||||
void *value = ref;
|
||||
if (typeId & asTYPEID_OBJHANDLE)
|
||||
value = *(void **)value;
|
||||
|
||||
asIScriptObject *obj = (asIScriptObject *)value;
|
||||
|
||||
if (obj) {
|
||||
for (asUINT n = 0; n < obj->GetPropertyCount(); n++) {
|
||||
auto id = obj->GetPropertyTypeId(n);
|
||||
auto data = obj->GetAddressOfProperty(n);
|
||||
auto ret = append2Ref(data, id);
|
||||
if (!ret) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Dereference handles, so we can see what it points to
|
||||
void *value = ref;
|
||||
|
||||
if (typeId & asTYPEID_OBJHANDLE)
|
||||
value = *(void **)value;
|
||||
|
||||
if (engine) {
|
||||
asITypeInfo *type = engine->GetTypeInfoById(typeId);
|
||||
if (value) {
|
||||
// only string supported
|
||||
if (type->GetTypeId() == (typeId & ~asTYPEID_OBJHANDLE)) {
|
||||
return emit controller.appendString(
|
||||
*reinterpret_cast<QString *>(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
qsizetype WingAngelAPI::getAsTypeSize(int typeId, void *data) {
|
||||
if (typeId == asTYPEID_VOID)
|
||||
return false;
|
||||
|
@ -1904,7 +1560,7 @@ int WingAngelAPI::qvariantCastASID(asIScriptEngine *engine,
|
|||
|
||||
bool WingAngelAPI::isTempBuffered(QMetaType::Type type) {
|
||||
switch (type) {
|
||||
case QMetaType::Type::Bool:
|
||||
case QMetaType::Bool:
|
||||
case QMetaType::Short:
|
||||
case QMetaType::UShort:
|
||||
case QMetaType::Int:
|
||||
|
@ -1997,6 +1653,52 @@ void WingAngelAPI::script_call(asIScriptGeneric *gen) {
|
|||
std::bind(op, gen, std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
bool WingAngelAPI::execScriptCode(const QString &code) {
|
||||
if (code.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_console) {
|
||||
QTemporaryFile f;
|
||||
if (f.open()) {
|
||||
f.write(code.toUtf8());
|
||||
f.close();
|
||||
}
|
||||
|
||||
_console->setMode(ScriptingConsole::Output);
|
||||
_console->write(QStringLiteral("(") %
|
||||
property("__LAST_CALLER__").toString() %
|
||||
QStringLiteral(") "));
|
||||
_console->machine()->executeScript(f.fileName());
|
||||
_console->appendCommandPrompt();
|
||||
_console->setMode(ScriptingConsole::Input);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WingAngelAPI::execScript(const QString &fileName) {
|
||||
_console->setMode(ScriptingConsole::Output);
|
||||
_console->write(QStringLiteral("(") %
|
||||
property("__LAST_CALLER__").toString() %
|
||||
QStringLiteral(") "));
|
||||
auto ret = _console->machine()->executeScript(fileName);
|
||||
_console->appendCommandPrompt();
|
||||
_console->setMode(ScriptingConsole::Input);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool WingAngelAPI::execCode(const QString &code) {
|
||||
_console->setMode(ScriptingConsole::Output);
|
||||
_console->write(QStringLiteral("(") %
|
||||
property("__LAST_CALLER__").toString() %
|
||||
QStringLiteral(") "));
|
||||
auto ret = _console->machine()->executeCode(code);
|
||||
_console->appendCommandPrompt();
|
||||
_console->setMode(ScriptingConsole::Input);
|
||||
return ret;
|
||||
}
|
||||
|
||||
QString WingAngelAPI::_InputBox_getItem(int stringID, const QString &title,
|
||||
const QString &label,
|
||||
const CScriptArray &items, int current,
|
||||
|
@ -2068,22 +1770,6 @@ CScriptArray *WingAngelAPI::_HexReader_readBytes(qsizetype offset,
|
|||
});
|
||||
}
|
||||
|
||||
bool WingAngelAPI::_HexReader_read(qsizetype offset, void *ref, int typeId) {
|
||||
return read2Ref(offset, ref, typeId);
|
||||
}
|
||||
|
||||
bool WingAngelAPI::_HexReader_write(qsizetype offset, void *ref, int typeId) {
|
||||
return write2Ref(offset, ref, typeId);
|
||||
}
|
||||
|
||||
bool WingAngelAPI::_HexReader_insert(qsizetype offset, void *ref, int typeId) {
|
||||
return insert2Ref(offset, ref, typeId);
|
||||
}
|
||||
|
||||
bool WingAngelAPI::_HexReader_append(void *ref, int typeId) {
|
||||
return append2Ref(ref, typeId);
|
||||
}
|
||||
|
||||
qsizetype WingAngelAPI::_HexReader_searchForward(qsizetype begin,
|
||||
const CScriptArray &ba) {
|
||||
// If called from the script, there will always be an active
|
||||
|
@ -2263,3 +1949,9 @@ bool WingAngelAPI::_DataVisual_updateTextTable(
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ScriptingConsole *WingAngelAPI::bindingConsole() const { return _console; }
|
||||
|
||||
void WingAngelAPI::setBindingConsole(ScriptingConsole *console) {
|
||||
_console = console;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
class asIScriptEngine;
|
||||
class ScriptMachine;
|
||||
class ScriptingConsole;
|
||||
|
||||
class WingAngelAPI : public WingHex::IWingPlugin {
|
||||
Q_OBJECT
|
||||
|
@ -46,12 +47,16 @@ public:
|
|||
virtual uint pluginVersion() const override;
|
||||
virtual const QString pluginComment() const override;
|
||||
|
||||
public:
|
||||
void
|
||||
registerScriptFns(const QString &ns,
|
||||
const QHash<QString, IWingPlugin::ScriptFnInfo> &rfns);
|
||||
|
||||
void installAPI(ScriptMachine *machine);
|
||||
|
||||
ScriptingConsole *bindingConsole() const;
|
||||
void setBindingConsole(ScriptingConsole *console);
|
||||
|
||||
private:
|
||||
void installLogAPI(asIScriptEngine *engine);
|
||||
void installExtAPI(asIScriptEngine *engine);
|
||||
|
@ -86,14 +91,6 @@ private:
|
|||
QByteArray cArray2ByteArray(const CScriptArray &array, int byteID,
|
||||
bool *ok = nullptr);
|
||||
|
||||
bool read2Ref(qsizetype offset, void *ref, int typeId);
|
||||
|
||||
bool write2Ref(qsizetype offset, void *ref, int typeId);
|
||||
|
||||
bool insert2Ref(qsizetype offset, void *ref, int typeId);
|
||||
|
||||
bool append2Ref(void *ref, int typeId);
|
||||
|
||||
qsizetype getAsTypeSize(int typeId, void *data);
|
||||
|
||||
template <typename T>
|
||||
|
@ -124,6 +121,11 @@ 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);
|
||||
|
||||
private:
|
||||
QString _InputBox_getItem(int stringID, const QString &title,
|
||||
const QString &label, const CScriptArray &items,
|
||||
|
@ -142,14 +144,6 @@ private:
|
|||
|
||||
CScriptArray *_HexReader_readBytes(qsizetype offset, qsizetype len);
|
||||
|
||||
bool _HexReader_read(qsizetype offset, void *ref, int typeId);
|
||||
|
||||
bool _HexReader_write(qsizetype offset, void *ref, int typeId);
|
||||
|
||||
bool _HexReader_insert(qsizetype offset, void *ref, int typeId);
|
||||
|
||||
bool _HexReader_append(void *ref, int typeId);
|
||||
|
||||
qsizetype _HexReader_searchForward(qsizetype begin, const CScriptArray &ba);
|
||||
|
||||
qsizetype _HexReader_searchBackward(qsizetype begin,
|
||||
|
@ -180,6 +174,8 @@ private:
|
|||
std::vector<std::any> _fnbuffer;
|
||||
QVector<IWingPlugin::ScriptFnInfo> _sfns;
|
||||
|
||||
ScriptingConsole *_console = nullptr;
|
||||
|
||||
QHash<QString, QHash<QString, qsizetype>> _rfns;
|
||||
};
|
||||
|
||||
|
|
|
@ -170,8 +170,7 @@ void EditorView::registerQMenu(QMenu *menu) {
|
|||
m_menu->addMenu(menu);
|
||||
}
|
||||
|
||||
EditorView::FindError EditorView::find(const QByteArray &data,
|
||||
const FindDialog::Result &result) {
|
||||
EditorView::FindError EditorView::find(const FindDialog::Result &result) {
|
||||
if (m_findMutex.tryLock(3000)) {
|
||||
std::unique_lock<QMutex> locker(m_findMutex, std::adopt_lock_t());
|
||||
auto d = m_hex->document();
|
||||
|
@ -196,19 +195,41 @@ EditorView::FindError EditorView::find(const QByteArray &data,
|
|||
end = -1;
|
||||
} break;
|
||||
}
|
||||
|
||||
QByteArray data;
|
||||
|
||||
if (result.isStringFind) {
|
||||
data = Utilities::encodingString(result.str, result.encoding);
|
||||
} else {
|
||||
data = result.buffer;
|
||||
}
|
||||
|
||||
d->findAllBytes(begin, end, data, results);
|
||||
|
||||
m_findResults->beginUpdate();
|
||||
m_findResults->clear();
|
||||
for (auto &result : results) {
|
||||
|
||||
auto lineWidth = m_hex->renderer()->hexLineWidth();
|
||||
for (auto &ritem : results) {
|
||||
FindResult r;
|
||||
r.offset = result;
|
||||
r.line = r.offset / m_hex->renderer()->hexLineWidth();
|
||||
r.col = r.offset % m_hex->renderer()->hexLineWidth();
|
||||
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->lastFindData() = data.toHex(' ').toUpper();
|
||||
m_findResults->endUpdate();
|
||||
|
||||
if (m_findResults->size() ==
|
||||
|
|
|
@ -92,7 +92,7 @@ public slots:
|
|||
void switchView(WingEditorViewWidget *w);
|
||||
void registerQMenu(QMenu *menu);
|
||||
|
||||
FindError find(const QByteArray &data, const FindDialog::Result &result);
|
||||
FindError find(const FindDialog::Result &result);
|
||||
|
||||
void clearFindResult();
|
||||
|
||||
|
|
|
@ -0,0 +1,257 @@
|
|||
/*==============================================================================
|
||||
** 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 "qtlonglongspinbox.h"
|
||||
|
||||
#include <QEvent>
|
||||
#include <QKeyEvent>
|
||||
#include <QLineEdit>
|
||||
#include <limits>
|
||||
|
||||
QtLongLongSpinBox::QtLongLongSpinBox(QWidget *parent)
|
||||
: QAbstractSpinBox(parent) {
|
||||
m_minimum = std::numeric_limits<qlonglong>::min();
|
||||
m_maximum = std::numeric_limits<qlonglong>::max();
|
||||
m_value = 0;
|
||||
m_singleStep = 1;
|
||||
m_base = 10;
|
||||
|
||||
setValue(m_value);
|
||||
}
|
||||
|
||||
qlonglong QtLongLongSpinBox::value() const { return m_value; }
|
||||
|
||||
void QtLongLongSpinBox::setValue(qlonglong expectedNewValue) {
|
||||
const qlonglong newValue = qBound(m_minimum, expectedNewValue, m_maximum);
|
||||
const QString newValueString = QString::number(newValue, m_base);
|
||||
lineEdit()->setText(m_prefix + newValueString + m_suffix);
|
||||
if (m_value != newValue) {
|
||||
m_value = newValue;
|
||||
emit valueChanged(newValue);
|
||||
}
|
||||
}
|
||||
|
||||
QString QtLongLongSpinBox::prefix() const { return m_prefix; }
|
||||
|
||||
void QtLongLongSpinBox::setPrefix(const QString &prefix) {
|
||||
m_prefix = prefix;
|
||||
|
||||
setValue(m_value);
|
||||
}
|
||||
|
||||
QString QtLongLongSpinBox::suffix() const { return m_suffix; }
|
||||
|
||||
void QtLongLongSpinBox::setSuffix(const QString &suffix) {
|
||||
m_suffix = suffix;
|
||||
|
||||
setValue(m_value);
|
||||
}
|
||||
|
||||
QString QtLongLongSpinBox::cleanText() const {
|
||||
return QString::number(m_value);
|
||||
}
|
||||
|
||||
qlonglong QtLongLongSpinBox::singleStep() const { return m_singleStep; }
|
||||
|
||||
void QtLongLongSpinBox::setSingleStep(qlonglong step) { m_singleStep = step; }
|
||||
|
||||
qlonglong QtLongLongSpinBox::minimum() const { return m_minimum; }
|
||||
|
||||
void QtLongLongSpinBox::setMinimum(qlonglong min) {
|
||||
m_minimum = min;
|
||||
if (m_maximum < m_minimum) {
|
||||
m_maximum = m_minimum;
|
||||
}
|
||||
|
||||
setValue(m_value);
|
||||
}
|
||||
|
||||
qlonglong QtLongLongSpinBox::maximum() const { return m_maximum; }
|
||||
|
||||
void QtLongLongSpinBox::setMaximum(qlonglong max) {
|
||||
m_maximum = max;
|
||||
if (m_maximum < m_minimum) {
|
||||
m_maximum = m_minimum;
|
||||
}
|
||||
|
||||
setValue(m_value);
|
||||
}
|
||||
|
||||
void QtLongLongSpinBox::setRange(qlonglong min, qlonglong max) {
|
||||
if (min < max) {
|
||||
m_minimum = min;
|
||||
m_maximum = max;
|
||||
} else {
|
||||
m_minimum = max;
|
||||
m_maximum = min;
|
||||
}
|
||||
|
||||
setValue(m_value);
|
||||
}
|
||||
|
||||
void QtLongLongSpinBox::setDisplayIntegerBase(int base) {
|
||||
if (m_base != base) {
|
||||
m_base = base;
|
||||
setValue(m_value);
|
||||
}
|
||||
}
|
||||
|
||||
int QtLongLongSpinBox::displayIntegerBase() const { return m_base; }
|
||||
|
||||
void QtLongLongSpinBox::keyPressEvent(QKeyEvent *event) {
|
||||
switch (event->key()) {
|
||||
case Qt::Key_Enter:
|
||||
case Qt::Key_Return:
|
||||
selectCleanText();
|
||||
lineEditEditingFinalize();
|
||||
}
|
||||
|
||||
QAbstractSpinBox::keyPressEvent(event);
|
||||
}
|
||||
|
||||
void QtLongLongSpinBox::focusOutEvent(QFocusEvent *event) {
|
||||
lineEditEditingFinalize();
|
||||
|
||||
QAbstractSpinBox::focusOutEvent(event);
|
||||
}
|
||||
|
||||
QAbstractSpinBox::StepEnabled QtLongLongSpinBox::stepEnabled() const {
|
||||
if (isReadOnly()) {
|
||||
return StepNone;
|
||||
}
|
||||
|
||||
StepEnabled se = StepNone;
|
||||
if (wrapping() || m_value < m_maximum) {
|
||||
se |= StepUpEnabled;
|
||||
}
|
||||
if (wrapping() || m_value > m_minimum) {
|
||||
se |= StepDownEnabled;
|
||||
}
|
||||
|
||||
return se;
|
||||
}
|
||||
|
||||
void QtLongLongSpinBox::stepBy(int steps) {
|
||||
if (isReadOnly()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_prefix + QString::number(m_value) + m_suffix != lineEdit()->text()) {
|
||||
lineEditEditingFinalize();
|
||||
}
|
||||
|
||||
qlonglong newValue = m_value + (steps * m_singleStep);
|
||||
if (wrapping()) {
|
||||
// emulating the behavior of QSpinBox
|
||||
if (newValue > m_maximum) {
|
||||
if (m_value == m_maximum) {
|
||||
newValue = m_minimum;
|
||||
} else {
|
||||
newValue = m_maximum;
|
||||
}
|
||||
} else if (newValue < m_minimum) {
|
||||
if (m_value == m_minimum) {
|
||||
newValue = m_maximum;
|
||||
} else {
|
||||
newValue = m_minimum;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
newValue = qBound(m_minimum, newValue, m_maximum);
|
||||
}
|
||||
|
||||
setValue(newValue);
|
||||
selectCleanText();
|
||||
}
|
||||
|
||||
QValidator::State QtLongLongSpinBox::validate(QString &input, int &pos) const {
|
||||
// first, we try to interpret as a number without prefixes
|
||||
bool ok;
|
||||
const qlonglong value = input.toLongLong(&ok);
|
||||
if (input.isEmpty() || (ok && value <= m_maximum)) {
|
||||
input = m_prefix + input + m_suffix;
|
||||
pos += m_prefix.length();
|
||||
return QValidator::Acceptable;
|
||||
}
|
||||
|
||||
// if string of text editor aren't simple number, try to interpret it
|
||||
// as a number with prefix and suffix
|
||||
bool valid = true;
|
||||
if (!m_prefix.isEmpty() && !input.startsWith(m_prefix)) {
|
||||
valid = false;
|
||||
}
|
||||
if (!m_suffix.isEmpty() && !input.endsWith(m_suffix)) {
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
const int start = m_prefix.length();
|
||||
const int length = input.length() - start - m_suffix.length();
|
||||
|
||||
bool ok;
|
||||
const QString number = input.mid(start, length);
|
||||
const qlonglong value = number.toLongLong(&ok);
|
||||
if (number.isEmpty() || (ok && value <= m_maximum)) {
|
||||
return QValidator::Acceptable;
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise not acceptable
|
||||
return QValidator::Invalid;
|
||||
}
|
||||
|
||||
void QtLongLongSpinBox::lineEditEditingFinalize() {
|
||||
const QString text = lineEdit()->text();
|
||||
|
||||
// first, we try to read as a number without prefixes
|
||||
bool ok;
|
||||
qlonglong value = text.toLongLong(&ok);
|
||||
if (ok) {
|
||||
setValue(value);
|
||||
return;
|
||||
}
|
||||
|
||||
// if string of text editor aren't simple number, try to interpret it
|
||||
// as a number with prefix and suffix
|
||||
bool valid = true;
|
||||
if (!m_prefix.isEmpty() && !text.startsWith(m_prefix)) {
|
||||
valid = false;
|
||||
} else if (!m_suffix.isEmpty() && !text.endsWith(m_suffix)) {
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
const int start = m_prefix.length();
|
||||
const int length = text.length() - start - m_suffix.length();
|
||||
|
||||
bool ok;
|
||||
const qlonglong value = text.mid(start, length).toLongLong(&ok);
|
||||
if (ok) {
|
||||
setValue(value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise set old value
|
||||
setValue(m_value);
|
||||
}
|
||||
|
||||
void QtLongLongSpinBox::selectCleanText() {
|
||||
lineEdit()->setSelection(m_prefix.length(), lineEdit()->text().length() -
|
||||
m_prefix.length() -
|
||||
m_suffix.length());
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/*==============================================================================
|
||||
** 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 QTLONGLONGSPINBOX_H
|
||||
#define QTLONGLONGSPINBOX_H
|
||||
|
||||
#include <QAbstractSpinBox>
|
||||
#include <QtGlobal>
|
||||
|
||||
class QtLongLongSpinBox : public QAbstractSpinBox {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QtLongLongSpinBox(QWidget *parent = 0);
|
||||
|
||||
qlonglong value() const;
|
||||
|
||||
QString prefix() const;
|
||||
void setPrefix(const QString &prefix);
|
||||
|
||||
QString suffix() const;
|
||||
void setSuffix(const QString &suffix);
|
||||
|
||||
QString cleanText() const;
|
||||
|
||||
qlonglong singleStep() const;
|
||||
void setSingleStep(qlonglong val);
|
||||
|
||||
qlonglong minimum() const;
|
||||
void setMinimum(qlonglong min);
|
||||
|
||||
qlonglong maximum() const;
|
||||
void setMaximum(qlonglong max);
|
||||
|
||||
void setRange(qlonglong min, qlonglong max);
|
||||
|
||||
void setDisplayIntegerBase(int base);
|
||||
|
||||
int displayIntegerBase() const;
|
||||
|
||||
public slots:
|
||||
void setValue(qlonglong value);
|
||||
|
||||
signals:
|
||||
void valueChanged(qlonglong i);
|
||||
|
||||
protected:
|
||||
virtual void keyPressEvent(QKeyEvent *event);
|
||||
virtual void focusOutEvent(QFocusEvent *event);
|
||||
virtual void stepBy(int steps);
|
||||
virtual StepEnabled stepEnabled() const;
|
||||
virtual QValidator::State validate(QString &input, int &pos) const;
|
||||
|
||||
private:
|
||||
void lineEditEditingFinalize();
|
||||
void selectCleanText();
|
||||
|
||||
private:
|
||||
QString m_prefix;
|
||||
QString m_suffix;
|
||||
qlonglong m_singleStep;
|
||||
qlonglong m_minimum;
|
||||
qlonglong m_maximum;
|
||||
qlonglong m_value;
|
||||
|
||||
int m_base;
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(QtLongLongSpinBox)
|
||||
};
|
||||
|
||||
#endif // QTLONGLONGSPINBOX_H
|
|
@ -25,14 +25,7 @@
|
|||
#include <QShortcut>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
#include <QStringDecoder>
|
||||
#else
|
||||
#include <QTextCodec>
|
||||
#endif
|
||||
|
||||
FindDialog::FindDialog(bool isBigFile, int start, int stop, bool sel,
|
||||
QWidget *parent)
|
||||
FindDialog::FindDialog(const FindInfo &info, QWidget *parent)
|
||||
: FramelessDialogBase(parent) {
|
||||
auto widget = new QWidget(this);
|
||||
auto layout = new QVBoxLayout(widget);
|
||||
|
@ -71,30 +64,44 @@ FindDialog::FindDialog(bool isBigFile, int start, int stop, bool sel,
|
|||
layout->addWidget(m_hexeditor);
|
||||
layout->addSpacing(10);
|
||||
|
||||
m_hex->setChecked(true);
|
||||
if (info.isStringFind) {
|
||||
m_string->setChecked(true);
|
||||
m_lineeditor->setEnabled(true);
|
||||
m_hex->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_lineeditor->setText(info.str);
|
||||
m_hexeditor->document()->_insert(0, info.buffer);
|
||||
|
||||
auto regionw = new QWidget(this);
|
||||
auto regionLayout = new QHBoxLayout(regionw);
|
||||
|
||||
regionLayout->addWidget(new QLabel(tr("Region:"), regionw));
|
||||
|
||||
m_regionStart = new QSpinBox(regionw);
|
||||
Q_ASSERT(stop >= start);
|
||||
m_regionStart->setRange(start, stop);
|
||||
m_regionStart = new QtLongLongSpinBox(regionw);
|
||||
Q_ASSERT(info.stop >= info.start);
|
||||
m_regionStart->setRange(info.start, info.stop);
|
||||
m_regionStart->setEnabled(false);
|
||||
m_regionStart->setValue(start);
|
||||
m_regionStart->setValue(info.start);
|
||||
m_regionStart->setDisplayIntegerBase(16);
|
||||
m_regionStart->setPrefix(QStringLiteral("0x"));
|
||||
regionLayout->addWidget(m_regionStart, 1);
|
||||
|
||||
regionLayout->addWidget(new QLabel(QStringLiteral(" - "), regionw));
|
||||
|
||||
m_regionStop = new QSpinBox(regionw);
|
||||
m_regionStop->setRange(start, stop);
|
||||
connect(m_regionStart, QOverload<int>::of(&QSpinBox::valueChanged),
|
||||
m_regionStop, &QSpinBox::setMinimum);
|
||||
m_regionStop = new QtLongLongSpinBox(regionw);
|
||||
m_regionStop->setRange(info.start, info.stop);
|
||||
connect(m_regionStart, &QtLongLongSpinBox::valueChanged, m_regionStop,
|
||||
&QtLongLongSpinBox::setMinimum);
|
||||
m_regionStop->setEnabled(false);
|
||||
m_regionStop->setValue(qMin(start + 1024 * 1024, stop));
|
||||
m_regionStop->setValue(qMin(info.start + 1024 * 1024, info.stop));
|
||||
m_regionStop->setDisplayIntegerBase(16);
|
||||
m_regionStop->setPrefix(QStringLiteral("0x"));
|
||||
regionLayout->addWidget(m_regionStop, 1);
|
||||
|
@ -118,7 +125,7 @@ FindDialog::FindDialog(bool isBigFile, int start, int stop, bool sel,
|
|||
}
|
||||
});
|
||||
group->addButton(b, id++);
|
||||
b->setEnabled(!isBigFile);
|
||||
b->setEnabled(!info.isBigFile);
|
||||
buttonLayout->addWidget(b);
|
||||
|
||||
b = new QPushButton(tr("Region"), this);
|
||||
|
@ -155,7 +162,7 @@ FindDialog::FindDialog(bool isBigFile, int start, int stop, bool sel,
|
|||
|
||||
b = new QPushButton(tr("Selection"), this);
|
||||
b->setCheckable(true);
|
||||
if (sel) {
|
||||
if (info.isSel) {
|
||||
connect(b, &QPushButton::toggled, this, [=](bool b) {
|
||||
if (b) {
|
||||
_result.dir = SearchDirection::Selection;
|
||||
|
@ -167,7 +174,7 @@ FindDialog::FindDialog(bool isBigFile, int start, int stop, bool sel,
|
|||
|
||||
group->addButton(b, id++);
|
||||
buttonLayout->addWidget(b);
|
||||
group->button(isBigFile ? 1 : 0)->setChecked(true);
|
||||
group->button(info.isBigFile ? 1 : 0)->setChecked(true);
|
||||
|
||||
layout->addWidget(btnBox);
|
||||
layout->addSpacing(20);
|
||||
|
@ -184,38 +191,20 @@ FindDialog::FindDialog(bool isBigFile, int start, int stop, bool sel,
|
|||
this->setWindowTitle(tr("find"));
|
||||
}
|
||||
|
||||
QByteArray FindDialog::getResult(Result &result) {
|
||||
FindDialog::Result FindDialog::getResult() const { return _result; }
|
||||
|
||||
void FindDialog::on_accept() {
|
||||
_result.start = 0;
|
||||
_result.stop = 0;
|
||||
if (m_regionStart->isEnabled()) {
|
||||
_result.start = m_regionStart->value();
|
||||
_result.stop = m_regionStop->value();
|
||||
}
|
||||
result = _result;
|
||||
return _findarr;
|
||||
}
|
||||
|
||||
void FindDialog::on_accept() {
|
||||
if (m_string->isChecked()) {
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
auto en = QStringConverter::encodingForName(
|
||||
m_encodings->currentText().toUtf8());
|
||||
Q_ASSERT(en.has_value());
|
||||
QStringEncoder e(en.value());
|
||||
_findarr = e.encode(m_lineeditor->text());
|
||||
#else
|
||||
auto en = QTextCodec::codecForName(m_encodings->currentText().toUtf8());
|
||||
auto e = en->makeEncoder();
|
||||
_findarr = e->fromUnicode(m_lineeditor->text());
|
||||
#endif
|
||||
} else {
|
||||
_findarr =
|
||||
m_hexeditor->document()->read(0, int(m_hexeditor->documentBytes()));
|
||||
}
|
||||
_result.encoding = m_encodings->currentText();
|
||||
_result.isStringFind = m_string->isChecked();
|
||||
_result.buffer = m_hexeditor->document()->read(0);
|
||||
_result.str = m_lineeditor->text();
|
||||
done(1);
|
||||
}
|
||||
|
||||
void FindDialog::on_reject() {
|
||||
_findarr.clear();
|
||||
done(0);
|
||||
}
|
||||
void FindDialog::on_reject() { done(0); }
|
||||
|
|
|
@ -19,13 +19,13 @@
|
|||
#define FINDDIALOG_H
|
||||
|
||||
#include "QHexView/qhexview.h"
|
||||
#include "control/qtlonglongspinbox.h"
|
||||
#include "framelessdialogbase.h"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QLineEdit>
|
||||
#include <QObject>
|
||||
#include <QRadioButton>
|
||||
#include <QSpinBox>
|
||||
|
||||
enum class SearchDirection { None, Region, Foreword, Backword, Selection };
|
||||
|
||||
|
@ -36,12 +36,30 @@ public:
|
|||
SearchDirection dir = SearchDirection::None;
|
||||
qsizetype start = 0;
|
||||
qsizetype stop = 0;
|
||||
|
||||
// for searching info
|
||||
bool isStringFind;
|
||||
QByteArray buffer;
|
||||
QString encoding;
|
||||
QString str;
|
||||
};
|
||||
|
||||
struct FindInfo {
|
||||
bool isBigFile;
|
||||
bool isStringFind;
|
||||
qlonglong start;
|
||||
qlonglong stop;
|
||||
bool isSel;
|
||||
|
||||
// for searching info
|
||||
QByteArray buffer;
|
||||
QString encoding;
|
||||
QString str;
|
||||
};
|
||||
|
||||
public:
|
||||
FindDialog(bool isBigFile, int start, int stop, bool sel = true,
|
||||
QWidget *parent = nullptr);
|
||||
QByteArray getResult(Result &result);
|
||||
explicit FindDialog(const FindInfo &info, QWidget *parent = nullptr);
|
||||
Result getResult() const;
|
||||
|
||||
private:
|
||||
void on_accept();
|
||||
|
@ -53,10 +71,9 @@ private:
|
|||
QRadioButton *m_string;
|
||||
QRadioButton *m_hex;
|
||||
QComboBox *m_encodings;
|
||||
QByteArray _findarr;
|
||||
|
||||
QSpinBox *m_regionStart;
|
||||
QSpinBox *m_regionStop;
|
||||
QtLongLongSpinBox *m_regionStart;
|
||||
QtLongLongSpinBox *m_regionStop;
|
||||
|
||||
Result _result;
|
||||
};
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "class/layoutmanager.h"
|
||||
#include "class/logger.h"
|
||||
#include "class/qkeysequences.h"
|
||||
#include "class/richtextitemdelegate.h"
|
||||
#include "class/scriptconsolemachine.h"
|
||||
#include "class/settingmanager.h"
|
||||
#include "class/wingfiledialog.h"
|
||||
|
@ -185,6 +186,8 @@ MainWindow::MainWindow(SplashDialog *splash) : FramelessMainWindow() {
|
|||
// load the model
|
||||
Q_ASSERT(m_scriptConsole && m_scriptConsole->machine());
|
||||
m_varshowtable->setModel(m_scriptConsole->consoleMachine()->model());
|
||||
|
||||
plg.angelApi()->setBindingConsole(m_scriptConsole);
|
||||
}
|
||||
|
||||
// connect settings signals
|
||||
|
@ -238,6 +241,8 @@ MainWindow::MainWindow(SplashDialog *splash) : FramelessMainWindow() {
|
|||
|
||||
this->setUpdatesEnabled(true);
|
||||
|
||||
plg.dispatchEvent(IWingPlugin::RegisteredEvent::AppReady, {});
|
||||
|
||||
if (splash)
|
||||
splash->setInfoText(tr("SetupFinished"));
|
||||
}
|
||||
|
@ -484,6 +489,9 @@ MainWindow::buildUpFindResultDock(ads::CDockManager *dock,
|
|||
m_findresult->addAction(newAction(QStringLiteral("del"),
|
||||
tr("ClearFindResult"),
|
||||
&MainWindow::on_clearfindresult));
|
||||
|
||||
m_findresult->setItemDelegate(new RichTextItemDelegate(m_findresult));
|
||||
|
||||
m_findresult->setModel(_findEmptyResult);
|
||||
|
||||
connect(m_findresult, &QTableView::doubleClicked, this,
|
||||
|
@ -1826,14 +1834,24 @@ void MainWindow::on_findfile() {
|
|||
return;
|
||||
}
|
||||
auto hexeditor = editor->hexEditor();
|
||||
FindDialog fd(editor->isBigFile(), 0, int(hexeditor->documentBytes()),
|
||||
hexeditor->selectionCount() == 1, this);
|
||||
|
||||
static FindDialog::FindInfo info;
|
||||
info.isBigFile = editor->isBigFile();
|
||||
info.start = 0;
|
||||
info.stop = hexeditor->documentBytes();
|
||||
info.isSel = hexeditor->selectionCount() == 1;
|
||||
|
||||
FindDialog fd(info, this);
|
||||
if (fd.exec()) {
|
||||
FindDialog::Result r;
|
||||
auto res = fd.getResult(r);
|
||||
auto r = fd.getResult();
|
||||
info.isStringFind = r.isStringFind;
|
||||
info.encoding = r.encoding;
|
||||
info.buffer = r.buffer;
|
||||
info.str = r.str;
|
||||
|
||||
ExecAsync<EditorView::FindError>(
|
||||
[this, r, res]() -> EditorView::FindError {
|
||||
return currentEditor()->find(res, r);
|
||||
[this, r]() -> EditorView::FindError {
|
||||
return currentEditor()->find(r);
|
||||
},
|
||||
[this](EditorView::FindError err) {
|
||||
switch (err) {
|
||||
|
@ -2262,7 +2280,10 @@ void MainWindow::on_exportfindresult() {
|
|||
if (f.open(QFile::WriteOnly)) {
|
||||
QJsonObject fobj;
|
||||
fobj.insert(QStringLiteral("file"), editor->fileName());
|
||||
fobj.insert(QStringLiteral("data"), findresitem->lastFindData());
|
||||
|
||||
// auto d= findresitem->lastFindData();
|
||||
|
||||
// fobj.insert(QStringLiteral("data"), findresitem->lastFindData());
|
||||
QJsonArray arr;
|
||||
for (int i = 0; i < c; i++) {
|
||||
auto data = findresitem->resultAt(i);
|
||||
|
@ -2371,6 +2392,19 @@ void MainWindow::on_locChanged() {
|
|||
_numsitem->setNumData(NumShowModel::NumTableIndex::Char, QString());
|
||||
}
|
||||
|
||||
auto cursor = hexeditor->cursor();
|
||||
|
||||
PluginSystem::instance().dispatchEvent(
|
||||
IWingPlugin::RegisteredEvent::CursorPositionChanged,
|
||||
{QVariant::fromValue(cursor->position())});
|
||||
}
|
||||
|
||||
void MainWindow::on_selectionChanged() {
|
||||
auto hexeditor = currentHexView();
|
||||
if (hexeditor == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 解码字符串
|
||||
auto cursor = hexeditor->cursor();
|
||||
QByteArrayList buffer;
|
||||
|
@ -2402,22 +2436,8 @@ void MainWindow::on_locChanged() {
|
|||
|
||||
// 如果不超过 10KB (默认)那么解码,防止太多卡死
|
||||
if (buffer.length() <= 1024 * _decstrlim) {
|
||||
auto encname = hexeditor->renderer()->encoding();
|
||||
if (encname == QStringLiteral("ASCII")) {
|
||||
encname = QStringLiteral("ISO-8859-1");
|
||||
}
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
auto enc = QStringConverter::encodingForName(encname.toUtf8());
|
||||
Q_ASSERT(enc.has_value());
|
||||
QStringDecoder dec(enc.value());
|
||||
|
||||
m_txtDecode->insertPlainText(dec.decode(b));
|
||||
#else
|
||||
auto enc = QTextCodec::codecForName(encname.toUtf8());
|
||||
auto dec = enc->makeDecoder();
|
||||
m_txtDecode->setText(dec->toUnicode(b));
|
||||
#endif
|
||||
m_txtDecode->insertPlainText(Utilities::decodingString(
|
||||
b, hexeditor->renderer()->encoding()));
|
||||
m_txtDecode->insertPlainText(QStringLiteral("\n"));
|
||||
} else {
|
||||
m_txtDecode->insertHtml(
|
||||
|
@ -2425,6 +2445,10 @@ void MainWindow::on_locChanged() {
|
|||
.arg(tr("TooManyBytesDecode")));
|
||||
}
|
||||
}
|
||||
|
||||
PluginSystem::instance().dispatchEvent(
|
||||
IWingPlugin::RegisteredEvent::SelectionChanged,
|
||||
{QVariant::fromValue(buffer), isPreview});
|
||||
}
|
||||
|
||||
void MainWindow::on_viewtxt() {
|
||||
|
@ -2621,6 +2645,9 @@ void MainWindow::registerEditorView(EditorView *editor) {
|
|||
auto ta = editor->toggleViewAction();
|
||||
menu->addAction(ta);
|
||||
ev->setEnabled(true);
|
||||
|
||||
PluginSystem::instance().dispatchEvent(
|
||||
IWingPlugin::RegisteredEvent::FileOpened, {editor->fileName()});
|
||||
}
|
||||
|
||||
void MainWindow::connectEditorView(EditorView *editor) {
|
||||
|
@ -2717,6 +2744,7 @@ void MainWindow::swapEditor(EditorView *old, EditorView *cur) {
|
|||
if (old != nullptr) {
|
||||
auto hexeditor = old->hexEditor();
|
||||
hexeditor->disconnect(SIGNAL(cursorLocationChanged()));
|
||||
hexeditor->disconnect(SIGNAL(cursorSelectionChanged()));
|
||||
hexeditor->disconnect(SIGNAL(canUndoChanged(bool)));
|
||||
hexeditor->disconnect(SIGNAL(canRedoChanged(bool)));
|
||||
hexeditor->disconnect(SIGNAL(documentSaved(bool)));
|
||||
|
@ -2731,6 +2759,8 @@ void MainWindow::swapEditor(EditorView *old, EditorView *cur) {
|
|||
auto hexeditor = cur->hexEditor();
|
||||
connect(hexeditor, &QHexView::cursorLocationChanged, this,
|
||||
&MainWindow::on_locChanged);
|
||||
connect(hexeditor, &QHexView::cursorSelectionChanged, this,
|
||||
&MainWindow::on_selectionChanged);
|
||||
connect(hexeditor, &QHexView::canUndoChanged, this, [this](bool b) {
|
||||
m_toolBtneditors[ToolButtonIndex::UNDO_ACTION]->setEnabled(b);
|
||||
});
|
||||
|
@ -2793,6 +2823,10 @@ void MainWindow::swapEditor(EditorView *old, EditorView *cur) {
|
|||
|
||||
m_curEditor = cur;
|
||||
hexeditor->getStatus();
|
||||
|
||||
PluginSystem::instance().dispatchEvent(
|
||||
IWingPlugin::RegisteredEvent::FileSwitched,
|
||||
{cur->fileName(), (old ? old->fileName() : QString())});
|
||||
}
|
||||
|
||||
void MainWindow::loadFindResult(EditorView *view) {
|
||||
|
@ -2971,6 +3005,8 @@ ErrFile MainWindow::saveEditor(EditorView *editor, const QString &filename,
|
|||
return ErrFile::Permission;
|
||||
}
|
||||
|
||||
auto oldName = editor->fileName();
|
||||
|
||||
QString workspace = m_views.value(editor);
|
||||
if (editor->change2WorkSpace()) {
|
||||
workspace = editor->fileName() + PROEXT;
|
||||
|
@ -2979,6 +3015,10 @@ ErrFile MainWindow::saveEditor(EditorView *editor, const QString &filename,
|
|||
auto ret = editor->save(workspace, filename, ignoreMd5, isExport);
|
||||
if (ret == ErrFile::Success) {
|
||||
m_views[editor] = workspace;
|
||||
|
||||
PluginSystem::instance().dispatchEvent(
|
||||
IWingPlugin::RegisteredEvent::FileSaved,
|
||||
{filename.isEmpty() ? oldName : filename, oldName});
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -3002,8 +3042,13 @@ ErrFile MainWindow::closeEditor(EditorView *editor, bool force) {
|
|||
m_curEditor = nullptr;
|
||||
_editorLock.unlock();
|
||||
}
|
||||
|
||||
auto fileName = editor->fileName();
|
||||
PluginSystem::instance().cleanUpEditorViewHandle(editor);
|
||||
editor->deleteDockWidget();
|
||||
PluginSystem::instance().dispatchEvent(
|
||||
IWingPlugin::RegisteredEvent::FileClosed, {fileName});
|
||||
|
||||
m_toolBtneditors.value(ToolButtonIndex::EDITOR_VIEWS)
|
||||
->setEnabled(m_views.size() != 0);
|
||||
|
||||
|
|
|
@ -188,6 +188,7 @@ private slots:
|
|||
void on_clearfindresult();
|
||||
void on_exportfindresult();
|
||||
void on_locChanged();
|
||||
void on_selectionChanged();
|
||||
|
||||
void on_viewtxt();
|
||||
void on_fullScreen();
|
||||
|
|
|
@ -21,15 +21,20 @@ FindResultModel::FindResultModel(QObject *parent)
|
|||
: QAbstractTableModel(parent) {}
|
||||
|
||||
int FindResultModel::rowCount(const QModelIndex &parent) const {
|
||||
Q_UNUSED(parent);
|
||||
return m_results.size();
|
||||
}
|
||||
|
||||
int FindResultModel::columnCount(const QModelIndex &parent) const { return 4; }
|
||||
int FindResultModel::columnCount(const QModelIndex &parent) const {
|
||||
Q_UNUSED(parent);
|
||||
return 5;
|
||||
}
|
||||
|
||||
QVariant FindResultModel::data(const QModelIndex &index, int role) const {
|
||||
switch (role) {
|
||||
case Qt::DisplayRole: {
|
||||
auto r = m_results.at(index.row());
|
||||
auto row = index.row();
|
||||
auto r = m_results.at(row);
|
||||
switch (index.column()) {
|
||||
case 0: // line
|
||||
return r.line;
|
||||
|
@ -38,8 +43,10 @@ QVariant FindResultModel::data(const QModelIndex &index, int role) const {
|
|||
case 2: // offset
|
||||
return QStringLiteral("0x") +
|
||||
QString::number(r.offset, 16).toUpper();
|
||||
case 3: // value
|
||||
return m_lastFindData;
|
||||
case 3: // range
|
||||
return m_lastFindData.at(row).findRange;
|
||||
case 4: // decoding
|
||||
return m_lastFindData.at(row).decoding;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
@ -62,6 +69,8 @@ QVariant FindResultModel::headerData(int section, Qt::Orientation orientation,
|
|||
return tr("offset");
|
||||
case 3:
|
||||
return tr("value");
|
||||
case 4:
|
||||
return tr("encoding");
|
||||
}
|
||||
} else {
|
||||
return section + 1;
|
||||
|
@ -72,7 +81,9 @@ QVariant FindResultModel::headerData(int section, Qt::Orientation orientation,
|
|||
|
||||
QList<WingHex::FindResult> &FindResultModel::results() { return m_results; }
|
||||
|
||||
QString &FindResultModel::lastFindData() { return m_lastFindData; }
|
||||
QList<FindResultModel::FindInfo> &FindResultModel::lastFindData() {
|
||||
return m_lastFindData;
|
||||
}
|
||||
|
||||
void FindResultModel::beginUpdate() { this->beginResetModel(); }
|
||||
|
||||
|
|
|
@ -19,15 +19,22 @@
|
|||
#define FINDRESULTMODEL_H
|
||||
|
||||
#include "plugin/iwingplugin.h"
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
|
||||
class FindResultModel : public QAbstractTableModel {
|
||||
Q_OBJECT
|
||||
public:
|
||||
struct FindInfo {
|
||||
QString findRange;
|
||||
QString decoding;
|
||||
};
|
||||
|
||||
public:
|
||||
explicit FindResultModel(QObject *parent = nullptr);
|
||||
|
||||
QList<WingHex::FindResult> &results();
|
||||
QString &lastFindData();
|
||||
QList<FindInfo> &lastFindData();
|
||||
|
||||
void beginUpdate();
|
||||
void endUpdate();
|
||||
|
@ -46,7 +53,7 @@ public:
|
|||
|
||||
private:
|
||||
QList<WingHex::FindResult> m_results;
|
||||
QString m_lastFindData;
|
||||
QList<FindInfo> m_lastFindData;
|
||||
};
|
||||
|
||||
#endif // FINDRESULTMODEL_H
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include <QFileDialog>
|
||||
#include <QInputDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QMetaObject>
|
||||
|
||||
/**
|
||||
* Don't try to modify this file, unless you are the dev
|
||||
|
@ -50,7 +51,7 @@ namespace WingHex {
|
|||
|
||||
using qusizetype = QIntegerForSizeof<std::size_t>::Unsigned;
|
||||
|
||||
Q_DECL_UNUSED constexpr auto SDKVERSION = 14;
|
||||
Q_DECL_UNUSED constexpr auto SDKVERSION = 15;
|
||||
|
||||
Q_DECL_UNUSED static QString PLUGINDIR() {
|
||||
return QCoreApplication::applicationDirPath() + QStringLiteral("/plugin");
|
||||
|
@ -490,6 +491,22 @@ signals:
|
|||
void raiseView();
|
||||
};
|
||||
|
||||
struct WingDependency {
|
||||
QString puid;
|
||||
uint version;
|
||||
QString md5; // optional, but recommend
|
||||
};
|
||||
|
||||
#ifdef WING_SERVICE
|
||||
#undef WING_SERVICE
|
||||
#endif
|
||||
|
||||
#define WING_SERVICE Q_INVOKABLE
|
||||
|
||||
// for bad broken Qt API
|
||||
#define WINGAPI_ARG(type, data) QArgument<type>(#type, data)
|
||||
#define WINGAPI_RETURN_ARG(type, data) QReturnArgument<type>(#type, data)
|
||||
|
||||
class IWingPlugin : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
@ -519,6 +536,7 @@ public:
|
|||
MetaTypeMask = 0xFFFFF,
|
||||
Ref = 0x10000000,
|
||||
Array = 0x100000,
|
||||
Map = 0x200000
|
||||
};
|
||||
|
||||
static_assert(MetaType::MetaMax < MetaType::Array);
|
||||
|
@ -531,11 +549,18 @@ public:
|
|||
|
||||
enum class RegisteredEvent : uint {
|
||||
None,
|
||||
SelectionChanged = 1u,
|
||||
CursorPositionChanged = 1u << 1
|
||||
AppReady = 1u,
|
||||
SelectionChanged = 1u << 1,
|
||||
CursorPositionChanged = 1u << 2,
|
||||
FileOpened = 1u << 3,
|
||||
FileSaved = 1u << 4,
|
||||
FileSwitched = 1u << 5,
|
||||
FileClosed = 1u << 6
|
||||
};
|
||||
Q_DECLARE_FLAGS(RegisteredEvents, RegisteredEvent)
|
||||
|
||||
enum class PluginFileEvent { Opened, Saved, Switched, Closed };
|
||||
|
||||
public:
|
||||
virtual int sdkVersion() const = 0;
|
||||
virtual const QString signature() const = 0;
|
||||
|
@ -548,6 +573,13 @@ public:
|
|||
virtual uint pluginVersion() const = 0;
|
||||
virtual const QString pluginComment() const = 0;
|
||||
|
||||
virtual QList<WingDependency> dependencies() const { return {}; }
|
||||
|
||||
virtual RegisteredEvents registeredEvents() const {
|
||||
return RegisteredEvent::None;
|
||||
}
|
||||
|
||||
public:
|
||||
virtual QList<WingDockWidgetInfo> registeredDockWidgets() const {
|
||||
return {};
|
||||
}
|
||||
|
@ -564,22 +596,41 @@ public:
|
|||
return {};
|
||||
}
|
||||
|
||||
// QHash<function-name, fn>
|
||||
virtual QHash<QString, ScriptFnInfo> registeredScriptFn() { return {}; }
|
||||
|
||||
virtual RegisteredEvents registeredEvents() const {
|
||||
return RegisteredEvent::None;
|
||||
public:
|
||||
// QHash< function-name, fn >
|
||||
virtual QHash<QString, ScriptFnInfo> registeredScriptFns() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
// QHash< obj-names, decl-members >
|
||||
virtual QHash<QString, QStringList> registeredScriptObjs() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
signals:
|
||||
// QHash< obj-names, decl-members >
|
||||
bool registerScriptObj(const QString &obj, const QStringList &members);
|
||||
|
||||
public:
|
||||
virtual void eventSelectionChanged(const QByteArrayList &selections) {
|
||||
virtual void eventSelectionChanged(const QByteArrayList &selections,
|
||||
bool isPreview) {
|
||||
Q_UNUSED(selections);
|
||||
Q_UNUSED(isPreview);
|
||||
}
|
||||
|
||||
virtual void eventCursorPositionChanged(const WingHex::HexPosition &pos) {
|
||||
Q_UNUSED(pos);
|
||||
}
|
||||
|
||||
virtual void eventPluginFile(PluginFileEvent e, const QString &newfileName,
|
||||
const QString &oldfileName) {
|
||||
Q_UNUSED(e);
|
||||
Q_UNUSED(newfileName);
|
||||
Q_UNUSED(oldfileName);
|
||||
}
|
||||
|
||||
virtual void eventReady() {}
|
||||
|
||||
signals:
|
||||
// extension and exposed to WingHexAngelScript
|
||||
void toast(const QPixmap &icon, const QString &message);
|
||||
|
@ -591,8 +642,72 @@ signals:
|
|||
|
||||
// not available for AngelScript
|
||||
// only for plugin UI extenstion
|
||||
|
||||
QDialog *createDialog(QWidget *content);
|
||||
|
||||
bool invokeService(const QString &puid, const char *method,
|
||||
Qt::ConnectionType type, QGenericReturnArgument ret,
|
||||
QGenericArgument val0 = QGenericArgument(nullptr),
|
||||
QGenericArgument val1 = QGenericArgument(),
|
||||
QGenericArgument val2 = QGenericArgument(),
|
||||
QGenericArgument val3 = QGenericArgument(),
|
||||
QGenericArgument val4 = QGenericArgument(),
|
||||
QGenericArgument val5 = QGenericArgument(),
|
||||
QGenericArgument val6 = QGenericArgument(),
|
||||
QGenericArgument val7 = QGenericArgument(),
|
||||
QGenericArgument val8 = QGenericArgument(),
|
||||
QGenericArgument val9 = QGenericArgument());
|
||||
|
||||
public:
|
||||
inline bool invokeService(const QString &puid, const char *member,
|
||||
QGenericReturnArgument ret,
|
||||
QGenericArgument val0 = QGenericArgument(nullptr),
|
||||
QGenericArgument val1 = QGenericArgument(),
|
||||
QGenericArgument val2 = QGenericArgument(),
|
||||
QGenericArgument val3 = QGenericArgument(),
|
||||
QGenericArgument val4 = QGenericArgument(),
|
||||
QGenericArgument val5 = QGenericArgument(),
|
||||
QGenericArgument val6 = QGenericArgument(),
|
||||
QGenericArgument val7 = QGenericArgument(),
|
||||
QGenericArgument val8 = QGenericArgument(),
|
||||
QGenericArgument val9 = QGenericArgument()) {
|
||||
return emit invokeService(puid, member, Qt::AutoConnection, ret, val0,
|
||||
val1, val2, val3, val4, val5, val6, val7,
|
||||
val8, val9);
|
||||
}
|
||||
|
||||
inline bool invokeService(const QString &puid, const char *member,
|
||||
Qt::ConnectionType type, QGenericArgument val0,
|
||||
QGenericArgument val1 = QGenericArgument(),
|
||||
QGenericArgument val2 = QGenericArgument(),
|
||||
QGenericArgument val3 = QGenericArgument(),
|
||||
QGenericArgument val4 = QGenericArgument(),
|
||||
QGenericArgument val5 = QGenericArgument(),
|
||||
QGenericArgument val6 = QGenericArgument(),
|
||||
QGenericArgument val7 = QGenericArgument(),
|
||||
QGenericArgument val8 = QGenericArgument(),
|
||||
QGenericArgument val9 = QGenericArgument()) {
|
||||
return emit invokeService(puid, member, type, QGenericReturnArgument(),
|
||||
val0, val1, val2, val3, val4, val5, val6,
|
||||
val7, val8, val9);
|
||||
}
|
||||
|
||||
inline bool invokeService(const QString &puid, const char *member,
|
||||
QGenericArgument val0,
|
||||
QGenericArgument val1 = QGenericArgument(),
|
||||
QGenericArgument val2 = QGenericArgument(),
|
||||
QGenericArgument val3 = QGenericArgument(),
|
||||
QGenericArgument val4 = QGenericArgument(),
|
||||
QGenericArgument val5 = QGenericArgument(),
|
||||
QGenericArgument val6 = QGenericArgument(),
|
||||
QGenericArgument val7 = QGenericArgument(),
|
||||
QGenericArgument val8 = QGenericArgument(),
|
||||
QGenericArgument val9 = QGenericArgument()) {
|
||||
return emit invokeService(puid, member, Qt::AutoConnection,
|
||||
QGenericReturnArgument(), val0, val1, val2,
|
||||
val3, val4, val5, val6, val7, val8, val9);
|
||||
}
|
||||
|
||||
public:
|
||||
WingPlugin::Reader reader;
|
||||
WingPlugin::Controller controller;
|
||||
|
|
|
@ -47,7 +47,7 @@ PluginSystem::~PluginSystem() {
|
|||
qApp->exit(int(CrashCode::PluginSetting));
|
||||
}
|
||||
|
||||
for (auto &item : loadedplgs) {
|
||||
for (auto &item : _loadedplgs) {
|
||||
auto set = std::make_unique<QSettings>(
|
||||
udir.absoluteFilePath(item->metaObject()->className()),
|
||||
QSettings::Format::IniFormat);
|
||||
|
@ -56,10 +56,12 @@ PluginSystem::~PluginSystem() {
|
|||
}
|
||||
}
|
||||
|
||||
const QList<IWingPlugin *> &PluginSystem::plugins() const { return loadedplgs; }
|
||||
const QList<IWingPlugin *> &PluginSystem::plugins() const {
|
||||
return _loadedplgs;
|
||||
}
|
||||
|
||||
const IWingPlugin *PluginSystem::plugin(qsizetype index) const {
|
||||
return loadedplgs.at(index);
|
||||
return _loadedplgs.at(index);
|
||||
}
|
||||
|
||||
void PluginSystem::loadPlugin(const QFileInfo &fileinfo, const QDir &setdir) {
|
||||
|
@ -201,9 +203,82 @@ bool PluginSystem::closeEditor(IWingPlugin *plg, int handle, bool force) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void PluginSystem::dispatchEvent(IWingPlugin::RegisteredEvent event,
|
||||
const QVariantList ¶ms) {
|
||||
switch (event) {
|
||||
case WingHex::IWingPlugin::RegisteredEvent::SelectionChanged: {
|
||||
Q_ASSERT(params.size() == 2 &&
|
||||
params.at(0).canConvert<QByteArrayList>() &&
|
||||
params.at(1).canConvert<bool>());
|
||||
auto buffers = params.first().value<QByteArrayList>();
|
||||
auto isPreview = params.at(1).toBool();
|
||||
for (auto &plg : _evplgs[event]) {
|
||||
plg->eventSelectionChanged(buffers, isPreview);
|
||||
}
|
||||
} break;
|
||||
case WingHex::IWingPlugin::RegisteredEvent::CursorPositionChanged: {
|
||||
Q_ASSERT(params.size() == 1 && params.at(0).canConvert<QHexPosition>());
|
||||
auto cursor = params.at(0).value<QHexPosition>();
|
||||
HexPosition pos;
|
||||
pos.line = cursor.line;
|
||||
pos.column = cursor.column;
|
||||
pos.nibbleindex = cursor.nibbleindex;
|
||||
pos.lineWidth = cursor.lineWidth;
|
||||
for (auto &plg : _evplgs[event]) {
|
||||
plg->eventCursorPositionChanged(pos);
|
||||
}
|
||||
} break;
|
||||
case WingHex::IWingPlugin::RegisteredEvent::FileOpened: {
|
||||
Q_ASSERT(params.size() == 1);
|
||||
auto fileName = params.first().toString();
|
||||
Q_ASSERT(!fileName.isEmpty());
|
||||
for (auto &plg : _evplgs[event]) {
|
||||
plg->eventPluginFile(IWingPlugin::PluginFileEvent::Opened, fileName,
|
||||
{});
|
||||
}
|
||||
} break;
|
||||
case WingHex::IWingPlugin::RegisteredEvent::FileSaved: {
|
||||
Q_ASSERT(params.size() == 2);
|
||||
auto newFileName = params.at(0).toString();
|
||||
auto oldFileName = params.at(1).toString();
|
||||
Q_ASSERT(!newFileName.isEmpty() && !oldFileName.isEmpty());
|
||||
for (auto &plg : _evplgs[event]) {
|
||||
plg->eventPluginFile(IWingPlugin::PluginFileEvent::Saved,
|
||||
oldFileName, newFileName);
|
||||
}
|
||||
} break;
|
||||
case WingHex::IWingPlugin::RegisteredEvent::FileSwitched: {
|
||||
Q_ASSERT(params.size() == 2);
|
||||
auto newFileName = params.at(0).toString();
|
||||
auto oldFileName = params.at(1).toString();
|
||||
for (auto &plg : _evplgs[event]) {
|
||||
plg->eventPluginFile(IWingPlugin::PluginFileEvent::Switched,
|
||||
oldFileName, newFileName);
|
||||
}
|
||||
} break;
|
||||
case WingHex::IWingPlugin::RegisteredEvent::AppReady: {
|
||||
Q_ASSERT(params.isEmpty());
|
||||
for (auto &plg : _evplgs[event]) {
|
||||
plg->eventReady();
|
||||
}
|
||||
} break;
|
||||
case WingHex::IWingPlugin::RegisteredEvent::FileClosed: {
|
||||
Q_ASSERT(params.size() == 1);
|
||||
auto fileName = params.first().toString();
|
||||
Q_ASSERT(!fileName.isEmpty());
|
||||
for (auto &plg : _evplgs[event]) {
|
||||
plg->eventPluginFile(IWingPlugin::PluginFileEvent::Closed, fileName,
|
||||
{});
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void PluginSystem::registerFns(IWingPlugin *plg) {
|
||||
Q_ASSERT(plg);
|
||||
auto fns = plg->registeredScriptFn();
|
||||
auto fns = plg->registeredScriptFns();
|
||||
if (fns.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
@ -224,9 +299,48 @@ void PluginSystem::registerFns(IWingPlugin *plg) {
|
|||
_angelplg->registerScriptFns(plg->metaObject()->className(), rfns);
|
||||
}
|
||||
|
||||
void PluginSystem::registerEvents(IWingPlugin *plg) {
|
||||
Q_ASSERT(plg);
|
||||
auto evs = plg->registeredEvents();
|
||||
using FlagInt = decltype(evs)::Int;
|
||||
if (FlagInt(evs) == FlagInt(IWingPlugin::RegisteredEvent::None)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (evs.testFlag(IWingPlugin::RegisteredEvent::SelectionChanged)) {
|
||||
_evplgs[IWingPlugin::RegisteredEvent::SelectionChanged].append(plg);
|
||||
}
|
||||
|
||||
if (evs.testFlag(IWingPlugin::RegisteredEvent::CursorPositionChanged)) {
|
||||
_evplgs[IWingPlugin::RegisteredEvent::CursorPositionChanged].append(
|
||||
plg);
|
||||
}
|
||||
|
||||
if (evs.testFlag(IWingPlugin::RegisteredEvent::FileOpened)) {
|
||||
_evplgs[IWingPlugin::RegisteredEvent::FileOpened].append(plg);
|
||||
}
|
||||
|
||||
if (evs.testFlag(IWingPlugin::RegisteredEvent::FileSaved)) {
|
||||
_evplgs[IWingPlugin::RegisteredEvent::FileSaved].append(plg);
|
||||
}
|
||||
|
||||
if (evs.testFlag(IWingPlugin::RegisteredEvent::FileSwitched)) {
|
||||
_evplgs[IWingPlugin::RegisteredEvent::FileSwitched].append(plg);
|
||||
}
|
||||
|
||||
if (evs.testFlag(IWingPlugin::RegisteredEvent::AppReady)) {
|
||||
_evplgs[IWingPlugin::RegisteredEvent::AppReady].append(plg);
|
||||
}
|
||||
|
||||
if (evs.testFlag(IWingPlugin::RegisteredEvent::FileClosed)) {
|
||||
_evplgs[IWingPlugin::RegisteredEvent::FileClosed].append(plg);
|
||||
}
|
||||
}
|
||||
|
||||
QString PluginSystem::type2AngelScriptString(IWingPlugin::MetaType type,
|
||||
bool isArg) {
|
||||
bool isArray = type & WingHex::IWingPlugin::Array;
|
||||
bool isMap = type & WingHex::IWingPlugin::Map;
|
||||
bool isRef = type & WingHex::IWingPlugin::Ref;
|
||||
|
||||
QString retype;
|
||||
|
@ -282,10 +396,18 @@ QString PluginSystem::type2AngelScriptString(IWingPlugin::MetaType type,
|
|||
return {};
|
||||
}
|
||||
|
||||
if (isMap && isArray) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (isArray) {
|
||||
retype = QStringLiteral("array<") + retype + QStringLiteral(">");
|
||||
}
|
||||
|
||||
if (isMap) {
|
||||
retype = QStringLiteral("dictionary<") + retype + QStringLiteral(">");
|
||||
}
|
||||
|
||||
if (isRef) {
|
||||
if (isArg) {
|
||||
retype += QStringLiteral(" @out");
|
||||
|
@ -349,7 +471,7 @@ bool PluginSystem::loadPlugin(IWingPlugin *p,
|
|||
}
|
||||
|
||||
auto puid = getPUID(p);
|
||||
if (loadedpuid.contains(puid)) {
|
||||
if (_loadedpuid.contains(puid)) {
|
||||
throw tr("ErrLoadLoadedPlugin");
|
||||
}
|
||||
|
||||
|
@ -374,8 +496,8 @@ bool PluginSystem::loadPlugin(IWingPlugin *p,
|
|||
}
|
||||
}
|
||||
|
||||
loadedplgs.push_back(p);
|
||||
loadedpuid << puid;
|
||||
_loadedplgs.push_back(p);
|
||||
_loadedpuid << puid;
|
||||
|
||||
Logger::warning(tr("PluginName :") + p->pluginName());
|
||||
Logger::warning(tr("PluginAuthor :") + p->pluginAuthor());
|
||||
|
@ -543,6 +665,7 @@ bool PluginSystem::loadPlugin(IWingPlugin *p,
|
|||
}
|
||||
|
||||
registerFns(p);
|
||||
registerEvents(p);
|
||||
connectInterface(p);
|
||||
|
||||
m_plgviewMap.insert(p, nullptr);
|
||||
|
@ -609,6 +732,82 @@ void PluginSystem::connectBaseInterface(IWingPlugin *plg) {
|
|||
return nullptr;
|
||||
}
|
||||
});
|
||||
connect(
|
||||
plg,
|
||||
QOverload<const QString &, const char *, Qt::ConnectionType,
|
||||
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 {
|
||||
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();
|
||||
|
||||
// filter the evil call and report to log
|
||||
QVarLengthArray<char, 512> sig;
|
||||
int len = qstrlen(method);
|
||||
if (len <= 0)
|
||||
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()};
|
||||
size_t paramCount;
|
||||
constexpr auto maxParamCount =
|
||||
sizeof(typeNames) / sizeof(const char *);
|
||||
for (paramCount = 1; paramCount < maxParamCount; ++paramCount) {
|
||||
len = qstrlen(typeNames[paramCount]);
|
||||
if (len <= 0)
|
||||
break;
|
||||
sig.append(typeNames[paramCount], len);
|
||||
sig.append(',');
|
||||
}
|
||||
if (paramCount == 1)
|
||||
sig.append(')'); // no parameters
|
||||
else
|
||||
sig[sig.size() - 1] = ')';
|
||||
sig.append('\0');
|
||||
|
||||
// checking
|
||||
auto midx = meta->indexOfMethod(sig.constData());
|
||||
if (midx < 0) {
|
||||
auto norm = QMetaObject::normalizedSignature(sig.constData());
|
||||
midx = meta->indexOfMethod(norm.constData());
|
||||
if (midx < 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto m = meta->method(midx);
|
||||
|
||||
if (m.methodType() == QMetaMethod::Signal) {
|
||||
// report
|
||||
Logger::warning(packLogMessage(
|
||||
plg->metaObject()->className(),
|
||||
tr("[EvilCall]") %
|
||||
QString::fromLatin1(sig.data(), sig.length())));
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
void PluginSystem::connectReaderInterface(IWingPlugin *plg) {
|
||||
|
@ -873,7 +1072,7 @@ void PluginSystem::connectReaderInterface(IWingPlugin *plg) {
|
|||
}
|
||||
|
||||
_rwlock.unlock();
|
||||
return toByteArray(buffer, enco);
|
||||
return Utilities::decodingString(buffer, enco);
|
||||
}
|
||||
return QString();
|
||||
});
|
||||
|
@ -1155,7 +1354,7 @@ void PluginSystem::connectControllerInterface(IWingPlugin *plg) {
|
|||
enco = render->encoding();
|
||||
}
|
||||
|
||||
auto unicode = toByteArray(value, enco);
|
||||
auto unicode = Utilities::encodingString(value, enco);
|
||||
|
||||
_rwlock.lockForWrite();
|
||||
auto ret = doc->insert(offset, unicode);
|
||||
|
@ -1204,7 +1403,7 @@ void PluginSystem::connectControllerInterface(IWingPlugin *plg) {
|
|||
enco = render->encoding();
|
||||
}
|
||||
|
||||
auto unicode = toByteArray(value, enco);
|
||||
auto unicode = Utilities::encodingString(value, enco);
|
||||
_rwlock.lockForWrite();
|
||||
auto ret = doc->replace(offset, unicode);
|
||||
_rwlock.unlock();
|
||||
|
@ -1251,7 +1450,7 @@ void PluginSystem::connectControllerInterface(IWingPlugin *plg) {
|
|||
enco = render->encoding();
|
||||
}
|
||||
|
||||
auto unicode = toByteArray(value, enco);
|
||||
auto unicode = Utilities::encodingString(value, enco);
|
||||
_rwlock.lockForWrite();
|
||||
auto ret = doc->insert(offset, unicode);
|
||||
_rwlock.unlock();
|
||||
|
@ -2185,26 +2384,3 @@ EditorView *PluginSystem::pluginCurrentEditor(IWingPlugin *sender) const {
|
|||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QByteArray PluginSystem::toByteArray(const QString &buffer,
|
||||
const QString &encoding) {
|
||||
auto enn = encoding;
|
||||
|
||||
if (enn.isEmpty() || enn == QStringLiteral("ASCII")) {
|
||||
enn = QStringLiteral("ISO-8859-1");
|
||||
}
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
auto en = QStringConverter::encodingForName(enn.toUtf8());
|
||||
QByteArray unicode;
|
||||
if (en.has_value()) {
|
||||
QStringEncoder e(en.value());
|
||||
unicode = e.encode(buffer);
|
||||
}
|
||||
#else
|
||||
auto enc = QTextCodec::codecForName(enn.toUtf8());
|
||||
auto e = enc->makeEncoder();
|
||||
auto unicode = e->fromUnicode(buffer);
|
||||
#endif
|
||||
return unicode;
|
||||
}
|
||||
|
|
|
@ -121,8 +121,12 @@ public:
|
|||
|
||||
bool closeEditor(IWingPlugin *plg, int handle, bool force);
|
||||
|
||||
void dispatchEvent(IWingPlugin::RegisteredEvent event,
|
||||
const QVariantList ¶ms);
|
||||
|
||||
private:
|
||||
void registerFns(IWingPlugin *plg);
|
||||
void registerEvents(IWingPlugin *plg);
|
||||
|
||||
QString type2AngelScriptString(IWingPlugin::MetaType type, bool isArg);
|
||||
|
||||
|
@ -146,8 +150,6 @@ private:
|
|||
|
||||
EditorView *pluginCurrentEditor(IWingPlugin *sender) const;
|
||||
|
||||
QByteArray toByteArray(const QString &buffer, const QString &encoding);
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
T readBasicTypeContent(IWingPlugin *plg, qsizetype offset) {
|
||||
|
@ -228,8 +230,10 @@ private:
|
|||
|
||||
private:
|
||||
MainWindow *_win = nullptr;
|
||||
QStringList loadedpuid;
|
||||
QList<IWingPlugin *> loadedplgs;
|
||||
QStringList _loadedpuid;
|
||||
QList<IWingPlugin *> _loadedplgs;
|
||||
|
||||
QMap<IWingPlugin::RegisteredEvent, QList<IWingPlugin *>> _evplgs;
|
||||
|
||||
QHash<IWingPlugin *, EditorView *> m_plgviewMap;
|
||||
QHash<IWingPlugin *, QList<QPair<SharedUniqueId, EditorView *>>>
|
||||
|
|
|
@ -250,6 +250,47 @@ public:
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
static QByteArray encodingString(const QString &str,
|
||||
const QString &enc = {}) {
|
||||
auto encoding = enc;
|
||||
if (encoding.isEmpty() || encoding.compare(QStringLiteral("ASCII"),
|
||||
Qt::CaseInsensitive) == 0) {
|
||||
encoding = QStringLiteral("ISO-8859-1");
|
||||
}
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
auto en = QStringConverter::encodingForName(encoding.toUtf8());
|
||||
Q_ASSERT(en.has_value());
|
||||
QStringEncoder e(en.value());
|
||||
return e.encode(str);
|
||||
#else
|
||||
auto en = QTextCodec::codecForName(encoding.toUtf8());
|
||||
auto e = en->makeEncoder();
|
||||
return e->fromUnicode(str);
|
||||
#endif
|
||||
}
|
||||
|
||||
static QString decodingString(const QByteArray &buffer,
|
||||
const QString &enc = {}) {
|
||||
auto encoding = enc;
|
||||
if (encoding.isEmpty() || encoding.compare(QStringLiteral("ASCII"),
|
||||
Qt::CaseInsensitive) == 0) {
|
||||
encoding = QStringLiteral("ISO-8859-1");
|
||||
}
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
auto en = QStringConverter::encodingForName(encoding.toUtf8());
|
||||
Q_ASSERT(en.has_value());
|
||||
QStringDecoder dec(en.value());
|
||||
|
||||
return dec.decode(buffer);
|
||||
#else
|
||||
auto en = QTextCodec::codecForName(encoding.toUtf8());
|
||||
auto dec = en->makeDecoder();
|
||||
return dec->toUnicode(buffer);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#endif // UTILITIES_H
|
||||
|
|
Loading…
Reference in New Issue