Compare commits
7 Commits
d5a4095779
...
8e76d29707
Author | SHA1 | Date |
---|---|---|
|
8e76d29707 | |
|
7e33b3b87a | |
|
2a897e0099 | |
|
85cad2aa0e | |
|
3e3ca37642 | |
|
11e207f686 | |
|
db90ece792 |
|
@ -4,7 +4,6 @@
|
|||
#include "control/qcodecompletionwidget.h"
|
||||
#include "qdocumentline.h"
|
||||
#include "qformatscheme.h"
|
||||
#include "qlanguagefactory.h"
|
||||
#include "utilities.h"
|
||||
|
||||
#include "QConsoleIODevice.h"
|
||||
|
@ -23,7 +22,11 @@
|
|||
QConsoleWidget::QConsoleWidget(QWidget *parent)
|
||||
: QEditor(false, parent), mode_(Output) {
|
||||
iodevice_ = new QConsoleIODevice(this, this);
|
||||
m_doc->setProperty("console", QVariant::fromValue(inpos_));
|
||||
setAcceptDrops(false);
|
||||
setUndoRedoEnabled(false);
|
||||
setCursorMirrorEnabled(false);
|
||||
createSimpleBasicContextMenu(false, false);
|
||||
}
|
||||
|
||||
QConsoleWidget::~QConsoleWidget() {}
|
||||
|
@ -37,6 +40,7 @@ void QConsoleWidget::setMode(ConsoleMode m) {
|
|||
cursor.movePosition(QDocumentCursor::End);
|
||||
setCursor(cursor);
|
||||
inpos_ = cursor;
|
||||
m_doc->setProperty("console", QVariant::fromValue(inpos_));
|
||||
mode_ = Input;
|
||||
}
|
||||
|
||||
|
@ -54,8 +58,6 @@ QString QConsoleWidget::getCommandLine() {
|
|||
return code.replace(QChar::ParagraphSeparator, QChar::LineFeed);
|
||||
}
|
||||
|
||||
void QConsoleWidget::clear() { document()->clear(); }
|
||||
|
||||
void QConsoleWidget::handleReturnKey() {
|
||||
QString code = getCommandLine();
|
||||
|
||||
|
@ -131,8 +133,7 @@ void QConsoleWidget::keyPressEvent(QKeyEvent *e) {
|
|||
|
||||
// Allow cut only if the selection is limited to the interactive area ...
|
||||
if (e->key() == Qt::Key_X && e->modifiers() == Qt::ControlModifier) {
|
||||
if (selectionInEditZone)
|
||||
cut();
|
||||
cut();
|
||||
e->accept();
|
||||
return;
|
||||
}
|
||||
|
@ -144,8 +145,7 @@ void QConsoleWidget::keyPressEvent(QKeyEvent *e) {
|
|||
QApplication::clipboard()->mimeData();
|
||||
const QString text = clipboard->text();
|
||||
if (!text.isNull()) {
|
||||
textCursor.insertText(text/*,
|
||||
channelCharFormat(StandardInput)*/);
|
||||
textCursor.insertText(text);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -249,21 +249,6 @@ void QConsoleWidget::keyPressEvent(QKeyEvent *e) {
|
|||
}
|
||||
}
|
||||
|
||||
void QConsoleWidget::contextMenuEvent(QContextMenuEvent *event) {
|
||||
// QMenu *menu = createStandardContextMenu();
|
||||
|
||||
// QAction *a;
|
||||
// if ((a = menu->findChild<QAction *>("edit-cut")))
|
||||
// a->setEnabled(canCut());
|
||||
// if ((a = menu->findChild<QAction *>("edit-delete")))
|
||||
// a->setEnabled(canCut());
|
||||
// if ((a = menu->findChild<QAction *>("edit-paste")))
|
||||
// a->setEnabled(canPaste());
|
||||
|
||||
// menu->exec(event->globalPos());
|
||||
// delete menu;
|
||||
}
|
||||
|
||||
bool QConsoleWidget::isSelectionInEditZone() const {
|
||||
auto textCursor = this->cursor();
|
||||
if (!textCursor.hasSelection())
|
||||
|
@ -306,13 +291,17 @@ QString QConsoleWidget::getHistoryPath() {
|
|||
void QConsoleWidget::write(const QString &message, const QString &sfmtID) {
|
||||
auto tc = cursor();
|
||||
auto ascom = dynamic_cast<AsCompletion *>(completionEngine());
|
||||
Q_ASSERT(ascom);
|
||||
auto cw = ascom->codeCompletionWidget();
|
||||
|
||||
if (mode() == Output || (cw && cw->isCompleting())) {
|
||||
QCodeCompletionWidget *cw = nullptr;
|
||||
if (ascom) {
|
||||
cw = ascom->codeCompletionWidget();
|
||||
}
|
||||
|
||||
if (ascom == nullptr || mode() == Output || (cw && cw->isCompleting())) {
|
||||
// in output mode or completion messages are appended
|
||||
auto tc1 = tc;
|
||||
tc1.movePosition(QDocumentCursor::End);
|
||||
auto line = tc1.line();
|
||||
tc1.moveTo(line, line.length());
|
||||
|
||||
// check is cursor was not at the end
|
||||
// (e.g. had been moved per mouse action)
|
||||
|
@ -418,6 +407,12 @@ int QConsoleWidget::History::indexOf(bool dir, int from) const {
|
|||
return to;
|
||||
}
|
||||
|
||||
void QConsoleWidget::cut() {
|
||||
if (isSelectionInEditZone()) {
|
||||
QEditor::cut();
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////// Stream manipulators /////////////////////
|
||||
|
||||
QTextStream &waitForInput(QTextStream &s) {
|
||||
|
@ -439,6 +434,7 @@ QTextStream &outChannel(QTextStream &s) {
|
|||
d->setCurrentWriteChannel(STDOUT_FILENO);
|
||||
return s;
|
||||
}
|
||||
|
||||
QTextStream &errChannel(QTextStream &s) {
|
||||
QConsoleIODevice *d = qobject_cast<QConsoleIODevice *>(s.device());
|
||||
if (d)
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include <QTextStream>
|
||||
|
||||
#include "qeditor.h"
|
||||
#include "qlanguagefactory.h"
|
||||
|
||||
class QConsoleIODevice;
|
||||
|
||||
|
@ -34,8 +33,6 @@ public:
|
|||
// get the current command line
|
||||
QString getCommandLine();
|
||||
|
||||
void clear();
|
||||
|
||||
public slots:
|
||||
|
||||
// write to StandardOutput
|
||||
|
@ -56,7 +53,7 @@ protected:
|
|||
void handleReturnKey();
|
||||
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
void contextMenuEvent(QContextMenuEvent *event) override;
|
||||
|
||||
// Returns true if there is a selection in edit zone
|
||||
bool isSelectionInEditZone() const;
|
||||
// Returns true if cursor is in edit zone
|
||||
|
@ -66,6 +63,10 @@ protected:
|
|||
|
||||
static QString getHistoryPath();
|
||||
|
||||
// QEditor interface
|
||||
public slots:
|
||||
virtual void cut() override;
|
||||
|
||||
private:
|
||||
struct History {
|
||||
QStringList strings_;
|
||||
|
@ -91,8 +92,6 @@ private:
|
|||
QDocumentCursor inpos_;
|
||||
QString currentMultiLineCode_;
|
||||
QConsoleIODevice *iodevice_;
|
||||
|
||||
QLanguageFactory *m_language = nullptr;
|
||||
};
|
||||
|
||||
QTextStream &waitForInput(QTextStream &s);
|
||||
|
|
|
@ -4,7 +4,7 @@ project(QHexView LANGUAGES CXX)
|
|||
|
||||
find_package(
|
||||
Qt${QT_VERSION_MAJOR}
|
||||
COMPONENTS Widgets Gui
|
||||
COMPONENTS Widgets Gui Concurrent
|
||||
REQUIRED)
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR TRUE)
|
||||
|
@ -78,5 +78,6 @@ set_target_properties(
|
|||
CXX_STANDARD 17
|
||||
CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
target_link_libraries(QHexView PRIVATE Qt${QT_VERSION_MAJOR}::Widgets
|
||||
Qt${QT_VERSION_MAJOR}::Gui)
|
||||
target_link_libraries(
|
||||
QHexView PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Gui
|
||||
Qt${QT_VERSION_MAJOR}::Concurrent)
|
||||
|
|
|
@ -13,7 +13,10 @@ QFileBuffer::QFileBuffer(QObject *parent) : QHexBuffer(parent) {
|
|||
|
||||
QFileBuffer::~QFileBuffer() {}
|
||||
|
||||
uchar QFileBuffer::at(qsizetype idx) { return uchar(_chunks->data(idx, 1)[0]); }
|
||||
uchar QFileBuffer::at(qsizetype idx) {
|
||||
auto data = _chunks->data(idx, 1);
|
||||
return uchar(data[0]);
|
||||
}
|
||||
|
||||
qsizetype QFileBuffer::length() const { return _chunks->size(); }
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "hexcommand.h"
|
||||
|
||||
HexCommand::HexCommand(QHexBuffer *buffer, QHexCursor *cursor, int nibbleindex,
|
||||
HexCommand::HexCommand(QHexDocument *doc, QHexCursor *cursor, int nibbleindex,
|
||||
QUndoCommand *parent)
|
||||
: QUndoCommand(parent), m_buffer(buffer), m_offset(0), m_length(0),
|
||||
m_cursor(cursor), m_nibbleindex(nibbleindex) {}
|
||||
: QUndoCommand(parent), m_doc(doc), m_cursor(cursor), m_offset(0),
|
||||
m_length(0), m_nibbleindex(nibbleindex) {}
|
||||
|
|
|
@ -1,22 +1,24 @@
|
|||
#ifndef HEXCOMMAND_H
|
||||
#define HEXCOMMAND_H
|
||||
|
||||
#include "document/buffer/qhexbuffer.h"
|
||||
#include "document/qhexcursor.h"
|
||||
#include "document/qhexdocument.h"
|
||||
|
||||
#include <QUndoCommand>
|
||||
|
||||
class HexCommand : public QUndoCommand {
|
||||
public:
|
||||
HexCommand(QHexBuffer *buffer, QHexCursor *cursor, int nibbleindex,
|
||||
HexCommand(QHexDocument *doc, QHexCursor *cursor, int nibbleindex,
|
||||
QUndoCommand *parent = nullptr);
|
||||
|
||||
protected:
|
||||
QHexBuffer *m_buffer;
|
||||
QHexDocument *m_doc;
|
||||
QHexCursor *m_cursor;
|
||||
|
||||
qsizetype m_offset;
|
||||
qsizetype m_length;
|
||||
QByteArray m_data;
|
||||
|
||||
QHexCursor *m_cursor;
|
||||
int m_nibbleindex;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
#include "insertcommand.h"
|
||||
|
||||
InsertCommand::InsertCommand(QHexBuffer *buffer, qsizetype offset,
|
||||
const QByteArray &data, QHexCursor *cursor,
|
||||
InsertCommand::InsertCommand(QHexDocument *doc, QHexCursor *cursor,
|
||||
qsizetype offset, const QByteArray &data,
|
||||
int nibbleindex, QUndoCommand *parent)
|
||||
: HexCommand(buffer, cursor, nibbleindex, parent) {
|
||||
: HexCommand(doc, cursor, nibbleindex, parent) {
|
||||
m_offset = offset;
|
||||
m_data = data;
|
||||
m_length = data.length();
|
||||
}
|
||||
|
||||
void InsertCommand::undo() {
|
||||
m_buffer->remove(m_offset, m_data.length());
|
||||
m_doc->_remove(m_offset, m_data.length());
|
||||
m_cursor->setPos(m_offset, m_nibbleindex);
|
||||
}
|
||||
void InsertCommand::redo() {
|
||||
m_buffer->insert(m_offset, m_data);
|
||||
m_doc->_insert(m_offset, m_data);
|
||||
if (m_data.length() == 1 && m_nibbleindex) {
|
||||
m_cursor->setPos(m_offset, 0);
|
||||
} else {
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
|
||||
class InsertCommand : public HexCommand {
|
||||
public:
|
||||
InsertCommand(QHexBuffer *buffer, qsizetype offset, const QByteArray &data,
|
||||
QHexCursor *cursor, int nibbleindex,
|
||||
InsertCommand(QHexDocument *doc, QHexCursor *cursor, qsizetype offset,
|
||||
const QByteArray &data, int nibbleindex,
|
||||
QUndoCommand *parent = nullptr);
|
||||
void undo() override;
|
||||
void redo() override;
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
#include "removecommand.h"
|
||||
|
||||
RemoveCommand::RemoveCommand(QHexBuffer *buffer, qsizetype offset,
|
||||
RemoveCommand::RemoveCommand(QHexDocument *doc, qsizetype offset,
|
||||
qsizetype length, QHexCursor *cursor,
|
||||
int nibbleindex, QUndoCommand *parent)
|
||||
: HexCommand(buffer, cursor, nibbleindex, parent) {
|
||||
: HexCommand(doc, cursor, nibbleindex, parent) {
|
||||
m_offset = offset;
|
||||
m_length = length;
|
||||
m_data = m_buffer->read(m_offset, m_length);
|
||||
m_data = doc->read(m_offset, m_length);
|
||||
}
|
||||
|
||||
void RemoveCommand::undo() {
|
||||
m_buffer->insert(m_offset, m_data);
|
||||
m_doc->_insert(m_offset, m_data);
|
||||
if (m_length > 1) {
|
||||
m_cursor->setPos(m_offset + m_length - 1, 1);
|
||||
} else {
|
||||
|
@ -24,5 +24,5 @@ void RemoveCommand::undo() {
|
|||
|
||||
void RemoveCommand::redo() {
|
||||
m_cursor->setPos(m_offset, m_nibbleindex);
|
||||
m_buffer->remove(m_offset, m_length);
|
||||
m_doc->_remove(m_offset, m_length);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
class RemoveCommand : public HexCommand {
|
||||
public:
|
||||
RemoveCommand(QHexBuffer *buffer, qsizetype offset, qsizetype length,
|
||||
RemoveCommand(QHexDocument *doc, qsizetype offset, qsizetype length,
|
||||
QHexCursor *cursor, int nibbleindex,
|
||||
QUndoCommand *parent = nullptr);
|
||||
void undo() override;
|
||||
|
|
|
@ -1,22 +1,24 @@
|
|||
#include "replacecommand.h"
|
||||
#include "document/qhexdocument.h"
|
||||
|
||||
ReplaceCommand::ReplaceCommand(QHexBuffer *buffer, qsizetype offset,
|
||||
ReplaceCommand::ReplaceCommand(QHexDocument *doc, qsizetype offset,
|
||||
const QByteArray &data, QHexCursor *cursor,
|
||||
int nibbleindex, QUndoCommand *parent)
|
||||
: HexCommand(buffer, cursor, nibbleindex, parent) {
|
||||
: HexCommand(doc, cursor, nibbleindex, parent) {
|
||||
|
||||
m_offset = offset;
|
||||
m_data = data;
|
||||
m_length = data.length();
|
||||
m_olddata = m_buffer->read(m_offset, m_length);
|
||||
m_olddata = doc->read(m_offset, m_length);
|
||||
}
|
||||
|
||||
void ReplaceCommand::undo() {
|
||||
m_buffer->replace(m_offset, m_olddata);
|
||||
m_doc->_replace(m_offset, m_olddata);
|
||||
m_cursor->setPos(m_offset, m_nibbleindex);
|
||||
}
|
||||
|
||||
void ReplaceCommand::redo() {
|
||||
m_buffer->replace(m_offset, m_data);
|
||||
m_doc->_replace(m_offset, m_data);
|
||||
if (m_data.length() == 1 && m_nibbleindex) {
|
||||
m_cursor->setPos(m_offset, 0);
|
||||
} else {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
class ReplaceCommand : public HexCommand {
|
||||
public:
|
||||
ReplaceCommand(QHexBuffer *buffer, qsizetype offset, const QByteArray &data,
|
||||
ReplaceCommand(QHexDocument *doc, qsizetype offset, const QByteArray &data,
|
||||
QHexCursor *cursor, int nibbleindex,
|
||||
QUndoCommand *parent = nullptr);
|
||||
void undo() override;
|
||||
|
|
|
@ -93,6 +93,54 @@ bool QHexDocument::metafgVisible() { return m_metafg; }
|
|||
|
||||
bool QHexDocument::metaCommentVisible() { return m_metacomment; }
|
||||
|
||||
void QHexDocument::insertBookMarkAdjust(qsizetype offset, qsizetype length) {
|
||||
QMap<qsizetype, QString> bms;
|
||||
|
||||
#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());
|
||||
}
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
for (auto it = rmbegin; it != _bookmarks.end();) {
|
||||
it = _bookmarks.erase(it);
|
||||
}
|
||||
#else
|
||||
_bookmarks.erase(rmbegin, _bookmarks.cend());
|
||||
#endif
|
||||
|
||||
_bookmarks.insert(bms);
|
||||
}
|
||||
|
||||
void QHexDocument::removeBookMarkAdjust(qsizetype offset, qsizetype length) {
|
||||
QMap<qsizetype, QString> bms;
|
||||
|
||||
#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());
|
||||
}
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
for (auto it = rmbegin; it != _bookmarks.end();) {
|
||||
it = _bookmarks.erase(it);
|
||||
}
|
||||
#else
|
||||
_bookmarks.erase(rmbegin, _bookmarks.cend());
|
||||
#endif
|
||||
|
||||
_bookmarks.insert(bms);
|
||||
}
|
||||
|
||||
bool QHexDocument::isDocSaved() { return m_isSaved; }
|
||||
|
||||
void QHexDocument::setDocSaved(bool b) {
|
||||
|
@ -285,10 +333,7 @@ bool QHexDocument::insert(qsizetype offset, const QByteArray &data) {
|
|||
if (m_keepsize || m_readonly || m_islocked ||
|
||||
(offset < m_buffer->length() && m_metadata->hasMetadata()))
|
||||
return false;
|
||||
m_buffer->insert(offset, data);
|
||||
setDocSaved(false);
|
||||
emit documentChanged();
|
||||
return true;
|
||||
return this->_insert(offset, data);
|
||||
}
|
||||
|
||||
bool QHexDocument::replace(qsizetype offset, uchar b) {
|
||||
|
@ -300,16 +345,44 @@ bool QHexDocument::replace(qsizetype offset, uchar b) {
|
|||
bool QHexDocument::replace(qsizetype offset, const QByteArray &data) {
|
||||
if (m_readonly || m_islocked)
|
||||
return false;
|
||||
return this->_replace(offset, data);
|
||||
}
|
||||
|
||||
bool QHexDocument::remove(qsizetype offset, qsizetype len) {
|
||||
if (m_keepsize || m_readonly || m_islocked || m_metadata->hasMetadata())
|
||||
return false;
|
||||
return this->_remove(offset, len);
|
||||
}
|
||||
|
||||
bool QHexDocument::_insert(qsizetype offset, uchar b) {
|
||||
return this->_insert(offset, QByteArray(1, char(b)));
|
||||
}
|
||||
|
||||
bool QHexDocument::_insert(qsizetype offset, const QByteArray &data) {
|
||||
m_buffer->insert(offset, data);
|
||||
auto len = data.size();
|
||||
insertBookMarkAdjust(offset, len);
|
||||
m_metadata->insertAdjust(offset, len);
|
||||
setDocSaved(false);
|
||||
emit documentChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QHexDocument::_replace(qsizetype offset, uchar b) {
|
||||
return this->_replace(offset, QByteArray(1, char(b)));
|
||||
}
|
||||
|
||||
bool QHexDocument::_replace(qsizetype offset, const QByteArray &data) {
|
||||
m_buffer->replace(offset, data);
|
||||
setDocSaved(false);
|
||||
emit documentChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QHexDocument::remove(qsizetype offset, qsizetype len) {
|
||||
if (m_keepsize || m_readonly || m_islocked || m_metadata->hasMetadata())
|
||||
return false;
|
||||
bool QHexDocument::_remove(qsizetype offset, qsizetype len) {
|
||||
m_buffer->remove(offset, len);
|
||||
removeBookMarkAdjust(offset, len);
|
||||
m_metadata->removeAdjust(offset, len);
|
||||
setDocSaved(false);
|
||||
emit documentChanged();
|
||||
return true;
|
||||
|
@ -419,14 +492,12 @@ void QHexDocument::Replace(QHexCursor *cursor, qsizetype offset, uchar b,
|
|||
|
||||
void QHexDocument::Insert(QHexCursor *cursor, qsizetype offset,
|
||||
const QByteArray &data, int nibbleindex) {
|
||||
if (m_keepsize || m_readonly || m_islocked ||
|
||||
(offset < m_buffer->length() && m_metadata->hasMetadata()))
|
||||
if (m_keepsize || m_readonly || m_islocked)
|
||||
return;
|
||||
if (!m_metadata->hasMetadata())
|
||||
m_undostack->push(
|
||||
new InsertCommand(m_buffer, offset, data, cursor, nibbleindex));
|
||||
else
|
||||
m_buffer->insert(offset, data);
|
||||
|
||||
m_undostack->push(
|
||||
new InsertCommand(this, cursor, offset, data, nibbleindex));
|
||||
|
||||
emit documentChanged();
|
||||
}
|
||||
|
||||
|
@ -435,7 +506,7 @@ void QHexDocument::Replace(QHexCursor *cursor, qsizetype offset,
|
|||
if (m_readonly || m_islocked)
|
||||
return;
|
||||
m_undostack->push(
|
||||
new ReplaceCommand(m_buffer, offset, data, cursor, nibbleindex));
|
||||
new ReplaceCommand(this, offset, data, cursor, nibbleindex));
|
||||
emit documentChanged();
|
||||
}
|
||||
|
||||
|
@ -444,7 +515,7 @@ bool QHexDocument::Remove(QHexCursor *cursor, qsizetype offset, qsizetype len,
|
|||
if (m_keepsize || m_readonly || m_islocked || m_metadata->hasMetadata())
|
||||
return false;
|
||||
m_undostack->push(
|
||||
new RemoveCommand(m_buffer, offset, len, cursor, nibbleindex));
|
||||
new RemoveCommand(this, offset, len, cursor, nibbleindex));
|
||||
emit documentChanged();
|
||||
return true;
|
||||
}
|
||||
|
@ -518,3 +589,5 @@ QHexDocument *QHexDocument::fromStorageDriver(const QStorageInfo &storage,
|
|||
return fromLargeFile(storage.device(), readonly);
|
||||
#endif
|
||||
}
|
||||
|
||||
QHexBuffer *QHexDocument::buffer() const { return m_buffer; }
|
||||
|
|
|
@ -87,6 +87,9 @@ public:
|
|||
bool metabgVisible();
|
||||
bool metaCommentVisible();
|
||||
|
||||
void insertBookMarkAdjust(qsizetype offset, qsizetype length);
|
||||
void removeBookMarkAdjust(qsizetype offset, qsizetype length);
|
||||
|
||||
/*======================*/
|
||||
|
||||
public:
|
||||
|
@ -128,6 +131,12 @@ public slots:
|
|||
bool replace(qsizetype offset, const QByteArray &data);
|
||||
bool remove(qsizetype offset, qsizetype len);
|
||||
|
||||
bool _insert(qsizetype offset, uchar b);
|
||||
bool _insert(qsizetype offset, const QByteArray &data);
|
||||
bool _replace(qsizetype offset, uchar b);
|
||||
bool _replace(qsizetype offset, const QByteArray &data);
|
||||
bool _remove(qsizetype offset, qsizetype len);
|
||||
|
||||
/*================================*/
|
||||
|
||||
/*================================*/
|
||||
|
@ -154,6 +163,8 @@ public:
|
|||
static QHexDocument *fromStorageDriver(const QStorageInfo &storage,
|
||||
bool readonly = false);
|
||||
|
||||
QHexBuffer *buffer() const;
|
||||
|
||||
signals:
|
||||
|
||||
/*================================*/
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "commands/meta/metareplacecommand.h"
|
||||
|
||||
#include <QtAlgorithms>
|
||||
#include <QtConcurrent/QtConcurrentMap>
|
||||
|
||||
QHexMetadata::QHexMetadata(QUndoStack *undo, QObject *parent)
|
||||
: QObject(parent), m_undo(undo) {}
|
||||
|
@ -99,20 +100,7 @@ bool QHexMetadata::removeMetadata(const QHexMetadataItem &item) {
|
|||
}
|
||||
|
||||
void QHexMetadata::removeMetadata(qsizetype offset) {
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
m_metadata.erase(
|
||||
std::remove_if(m_metadata.begin(), m_metadata.end(),
|
||||
[offset, this](const QHexMetadataItem &item) {
|
||||
auto r = offset >= item.begin && offset <= item.end;
|
||||
if (r) {
|
||||
for (auto &l : m_linemeta) {
|
||||
l.remove(item);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}));
|
||||
#else
|
||||
m_metadata.removeIf([offset, this](const QHexMetadataItem &item) {
|
||||
auto rmfn = [offset, this](const QHexMetadataItem &item) {
|
||||
auto r = offset >= item.begin && offset <= item.end;
|
||||
if (r) {
|
||||
for (auto &l : m_linemeta) {
|
||||
|
@ -120,8 +108,16 @@ void QHexMetadata::removeMetadata(qsizetype offset) {
|
|||
}
|
||||
}
|
||||
return r;
|
||||
});
|
||||
};
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
m_metadata.erase(
|
||||
std::remove_if(m_metadata.begin(), m_metadata.end(), rmfn));
|
||||
#else
|
||||
m_metadata.removeIf(rmfn);
|
||||
#endif
|
||||
|
||||
emit metadataChanged();
|
||||
}
|
||||
|
||||
QVector<QHexMetadataItem> QHexMetadata::getAllMetadata() const {
|
||||
|
@ -187,12 +183,24 @@ void QHexMetadata::clear() {
|
|||
emit metadataChanged();
|
||||
}
|
||||
|
||||
void QHexMetadata::metadata(qsizetype begin, qsizetype end,
|
||||
bool QHexMetadata::metadata(qsizetype begin, qsizetype end,
|
||||
const QColor &fgcolor, const QColor &bgcolor,
|
||||
const QString &comment) {
|
||||
if (begin > end)
|
||||
return false;
|
||||
|
||||
if (!fgcolor.isValid() || fgcolor.alpha() == 0) {
|
||||
if (!bgcolor.isValid() || bgcolor.alpha() == 0) {
|
||||
if (comment.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QHexMetadataItem absi{begin, end, fgcolor, bgcolor, comment};
|
||||
addMetadata(absi);
|
||||
emit metadataChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
void QHexMetadata::setLineWidth(quint8 width) {
|
||||
|
@ -208,27 +216,86 @@ void QHexMetadata::setLineWidth(quint8 width) {
|
|||
}
|
||||
}
|
||||
|
||||
void QHexMetadata::color(qsizetype begin, qsizetype end, const QColor &fgcolor,
|
||||
void QHexMetadata::insertAdjust(qsizetype offset, qsizetype length) {
|
||||
m_linemeta.clear();
|
||||
|
||||
QtConcurrent::blockingMap(
|
||||
m_metadata, [offset, length](QHexMetadataItem &meta) {
|
||||
if (meta.end < offset) {
|
||||
return;
|
||||
}
|
||||
if (meta.begin <= offset && meta.end > offset) {
|
||||
meta.end += length;
|
||||
} else {
|
||||
meta.begin += length;
|
||||
meta.end += length;
|
||||
}
|
||||
});
|
||||
|
||||
for (auto &meta : m_metadata) {
|
||||
addMetaLines(meta);
|
||||
}
|
||||
}
|
||||
|
||||
void QHexMetadata::removeAdjust(qsizetype offset, qsizetype length) {
|
||||
m_linemeta.clear();
|
||||
|
||||
QtConcurrent::blockingMap(
|
||||
m_metadata, [offset, length](QHexMetadataItem &meta) {
|
||||
if (meta.end < offset) {
|
||||
return;
|
||||
}
|
||||
if (meta.begin <= offset && meta.end > offset) {
|
||||
meta.end -= length;
|
||||
if (meta.begin > meta.end) {
|
||||
meta.flag = true;
|
||||
}
|
||||
} else {
|
||||
meta.begin -= length;
|
||||
meta.end -= length;
|
||||
}
|
||||
});
|
||||
|
||||
auto rmfn = [](const QHexMetadataItem &meta) { return meta.flag; };
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
m_metadata.erase(
|
||||
std::remove_if(m_metadata.begin(), m_metadata.end(), rmfn));
|
||||
#else
|
||||
m_metadata.removeIf(rmfn);
|
||||
#endif
|
||||
|
||||
for (auto &meta : m_metadata) {
|
||||
addMetaLines(meta);
|
||||
}
|
||||
}
|
||||
|
||||
bool QHexMetadata::color(qsizetype begin, qsizetype end, const QColor &fgcolor,
|
||||
const QColor &bgcolor) {
|
||||
this->metadata(begin, end, fgcolor, bgcolor, QString());
|
||||
return this->metadata(begin, end, fgcolor, bgcolor, QString());
|
||||
}
|
||||
|
||||
void QHexMetadata::foreground(qsizetype begin, qsizetype end,
|
||||
bool QHexMetadata::foreground(qsizetype begin, qsizetype end,
|
||||
const QColor &fgcolor) {
|
||||
this->color(begin, end, fgcolor, QColor());
|
||||
return this->color(begin, end, fgcolor, QColor());
|
||||
}
|
||||
|
||||
void QHexMetadata::background(qsizetype begin, qsizetype end,
|
||||
bool QHexMetadata::background(qsizetype begin, qsizetype end,
|
||||
const QColor &bgcolor) {
|
||||
this->color(begin, end, QColor(), bgcolor);
|
||||
return this->color(begin, end, QColor(), bgcolor);
|
||||
}
|
||||
|
||||
void QHexMetadata::comment(qsizetype begin, qsizetype end,
|
||||
bool QHexMetadata::comment(qsizetype begin, qsizetype end,
|
||||
const QString &comment) {
|
||||
this->metadata(begin, end, QColor(), QColor(), comment);
|
||||
return this->metadata(begin, end, QColor(), QColor(), comment);
|
||||
}
|
||||
|
||||
void QHexMetadata::addMetadata(const QHexMetadataItem &mi) {
|
||||
addMetaLines(mi);
|
||||
m_metadata << mi;
|
||||
}
|
||||
|
||||
void QHexMetadata::addMetaLines(const QHexMetadataItem &mi) {
|
||||
const auto firstRow = mi.begin / m_lineWidth;
|
||||
const auto lastRow = mi.end / m_lineWidth;
|
||||
|
||||
|
@ -257,6 +324,4 @@ void QHexMetadata::addMetadata(const QHexMetadataItem &mi) {
|
|||
{start, length, mi.foreground, mi.background, mi.comment});
|
||||
}
|
||||
}
|
||||
|
||||
m_metadata << mi;
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ struct QHexMetadataItem {
|
|||
qsizetype end = -1;
|
||||
QColor foreground, background;
|
||||
QString comment;
|
||||
bool flag = false;
|
||||
|
||||
// added by wingsummer
|
||||
bool operator==(const QHexMetadataItem &item) const {
|
||||
|
@ -110,20 +111,25 @@ public:
|
|||
void clear();
|
||||
void setLineWidth(quint8 width);
|
||||
|
||||
void insertAdjust(qsizetype offset, qsizetype length);
|
||||
void removeAdjust(qsizetype offset, qsizetype length);
|
||||
|
||||
public:
|
||||
// new interface with begin, end
|
||||
void metadata(qsizetype begin, qsizetype end, const QColor &fgcolor,
|
||||
bool metadata(qsizetype begin, qsizetype end, const QColor &fgcolor,
|
||||
const QColor &bgcolor, const QString &comment);
|
||||
|
||||
void color(qsizetype begin, qsizetype end, const QColor &fgcolor,
|
||||
bool color(qsizetype begin, qsizetype end, const QColor &fgcolor,
|
||||
const QColor &bgcolor);
|
||||
void foreground(qsizetype begin, qsizetype end, const QColor &fgcolor);
|
||||
void background(qsizetype begin, qsizetype end, const QColor &bgcolor);
|
||||
void comment(qsizetype begin, qsizetype end, const QString &comment);
|
||||
bool foreground(qsizetype begin, qsizetype end, const QColor &fgcolor);
|
||||
bool background(qsizetype begin, qsizetype end, const QColor &bgcolor);
|
||||
bool comment(qsizetype begin, qsizetype end, const QString &comment);
|
||||
|
||||
private:
|
||||
void addMetadata(const QHexMetadataItem &mi);
|
||||
|
||||
void addMetaLines(const QHexMetadataItem &mi);
|
||||
|
||||
signals:
|
||||
void metadataChanged();
|
||||
|
||||
|
|
|
@ -797,12 +797,15 @@ bool QHexView::processAction(QHexCursor *cur, QKeyEvent *e) {
|
|||
|
||||
// modified by wingsummer
|
||||
if (isKeepSize()) {
|
||||
if (e->key() == Qt::Key_Backspace)
|
||||
m_document->Replace(m_cursor, cur->position().offset() - 1,
|
||||
uchar(0), 0);
|
||||
else
|
||||
m_document->Replace(m_cursor, cur->position().offset(),
|
||||
uchar(0), 0);
|
||||
if (cur->insertionMode() == QHexCursor::OverwriteMode) {
|
||||
if (e->key() == Qt::Key_Backspace)
|
||||
m_document->Replace(m_cursor,
|
||||
cur->position().offset() - 1,
|
||||
uchar(0), 0);
|
||||
else
|
||||
m_document->Replace(m_cursor, cur->position().offset(),
|
||||
uchar(0), 0);
|
||||
}
|
||||
} else {
|
||||
if (e->key() == Qt::Key_Backspace)
|
||||
m_document->Remove(m_cursor, cur->position().offset() - 1,
|
||||
|
@ -930,11 +933,12 @@ bool QHexView::processTextInput(QHexCursor *cur, QKeyEvent *e) {
|
|||
if (isReadOnly() || isLocked() || (e->modifiers() & Qt::ControlModifier))
|
||||
return false;
|
||||
|
||||
if (e->text().isEmpty()) {
|
||||
auto text = e->text();
|
||||
if (text.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uchar key = static_cast<uchar>(e->text()[0].toLatin1());
|
||||
uchar key = static_cast<uchar>(text[0].toLatin1());
|
||||
|
||||
if ((m_renderer->selectedArea() == QHexRenderer::HexArea)) {
|
||||
if (!((key >= '0' && key <= '9') ||
|
||||
|
|
|
@ -40,9 +40,7 @@ set(WIDGETS_SRC
|
|||
lib/widgets/qlinenumberpanel.cpp
|
||||
lib/widgets/qlinenumberpanel.h
|
||||
lib/widgets/qpanel.cpp
|
||||
lib/widgets/qpanel.h
|
||||
lib/widgets/qsimplecolorpicker.cpp
|
||||
lib/widgets/qsimplecolorpicker.h)
|
||||
lib/widgets/qpanel.h)
|
||||
|
||||
set(QNFA_SRC
|
||||
lib/qnfa/light_vector.h lib/qnfa/qnfadefinition.h lib/qnfa/qnfa.h
|
||||
|
|
|
@ -155,6 +155,8 @@ QString QDocument::screenable(const QChar *d, int l, int tabStop) {
|
|||
return fragment;
|
||||
}
|
||||
|
||||
int QDocument::lineSpacing() const { return m_impl->m_lineSpacing; }
|
||||
|
||||
struct InitStruct {
|
||||
InitStruct() {
|
||||
qRegisterMetaType<QDocumentIterator>("QDocumentIterator");
|
||||
|
@ -316,7 +318,7 @@ void QDocument::setText(const QString &s) {
|
|||
|
||||
// qDeleteAll(m_impl->m_lines);
|
||||
foreach (QDocumentLineHandle *h, m_impl->m_lines) {
|
||||
h->m_doc = 0;
|
||||
h->m_doc = nullptr;
|
||||
h->deref();
|
||||
}
|
||||
|
||||
|
@ -374,13 +376,8 @@ void QDocument::setText(const QString &s) {
|
|||
m_impl->m_lines << new QDocumentLineHandle(
|
||||
s.mid(last, s.length() - last), this);
|
||||
}
|
||||
//
|
||||
// if ( (idx > 0) && ((idx - 1) < s.length()) && ((s.at(idx - 1) == '\n')
|
||||
//|| (s.at(idx - 1) == '\r')) ) m_impl->m_lines << new
|
||||
// QDocumentLineHandle(this);
|
||||
//
|
||||
|
||||
// qDebug("[one go] dos : %i; nix : %i", m_impl->_dos, m_impl->_nix);
|
||||
m_impl->m_editCursor = new QDocumentCursor(this);
|
||||
|
||||
m_impl->m_lastModified = QDateTime::currentDateTime();
|
||||
|
||||
|
@ -421,7 +418,7 @@ void QDocument::startChunkLoading() {
|
|||
|
||||
// qDeleteAll(m_impl->m_lines);
|
||||
foreach (QDocumentLineHandle *h, m_impl->m_lines) {
|
||||
h->m_doc = 0;
|
||||
h->m_doc = nullptr;
|
||||
h->deref();
|
||||
}
|
||||
|
||||
|
@ -748,7 +745,7 @@ QFont QDocument::font() { return m_impl->m_font; }
|
|||
*/
|
||||
void QDocument::setFont(const QFont &f) {
|
||||
m_impl->setFont(f);
|
||||
// emit contentsChanged();
|
||||
emit fontChanged(f);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -2410,7 +2407,7 @@ void QDocumentLineHandle::draw(QPainter *p, int xOffset, int vWidth,
|
|||
p->drawLine(impl->m_leftMargin, 0, impl->m_leftMargin,
|
||||
impl->m_lineSpacing);
|
||||
|
||||
} else if (true) {
|
||||
} else {
|
||||
|
||||
QVector<quint16> merged;
|
||||
merged.fill(0, m_text.length());
|
||||
|
@ -2427,7 +2424,6 @@ void QDocumentLineHandle::draw(QPainter *p, int xOffset, int vWidth,
|
|||
// opverlays...
|
||||
|
||||
// merge selection ranges with the rest (formats + overlays)
|
||||
if (true) // m_composited.count() || sel.count() )
|
||||
{
|
||||
// int max = qMin(m_text.count(), m_composited.count());
|
||||
|
||||
|
@ -2865,216 +2861,6 @@ void QDocumentLineHandle::draw(QPainter *p, int xOffset, int vWidth,
|
|||
if (unbounded)
|
||||
p->fillRect(xpos, ypos, maxWidth - xpos, impl->m_lineSpacing,
|
||||
pal.highlight());
|
||||
|
||||
} else {
|
||||
QChar c;
|
||||
|
||||
int maxWidth = xOffset + vWidth;
|
||||
|
||||
const bool wrapped = m_frontiers.count();
|
||||
|
||||
int fmt = 0;
|
||||
|
||||
bool leading = true, unbounded = false, leftSel = false,
|
||||
showTabs = m_doc->showSpaces() & QDocument::ShowTabs,
|
||||
showLeading = m_doc->showSpaces() & QDocument::ShowLeading,
|
||||
showTrailing = m_doc->showSpaces() & QDocument::ShowTrailing;
|
||||
|
||||
int cwidth, ypos = 0, indent = 0, idx = 0, column = 0, selidx = 0,
|
||||
sellen = 0, wrap = 0, xpos = impl->m_leftMargin;
|
||||
|
||||
const int ts = m_doc->tabStop();
|
||||
|
||||
// find start of trailing whitespaces
|
||||
int last = m_text.length();
|
||||
|
||||
while ((last > 0) && m_text.at(last - 1).isSpace())
|
||||
--last;
|
||||
|
||||
// p->save();
|
||||
|
||||
// qDebug("drawing from %i to %i", xpos, maxWidth);
|
||||
|
||||
while (idx < m_text.length()) {
|
||||
if ((selidx < sel.count()) && (idx == sel[selidx])) {
|
||||
if ((selidx + 1) < sel.count()) {
|
||||
sellen = sel[selidx + 1] - sel[selidx];
|
||||
selidx += 2;
|
||||
} else {
|
||||
// unbounded selection
|
||||
unbounded = true;
|
||||
|
||||
++selidx;
|
||||
sellen = m_text.length() - idx;
|
||||
|
||||
p->fillRect(xpos, ypos, maxWidth - xpos,
|
||||
impl->m_lineSpacing, pal.highlight());
|
||||
}
|
||||
}
|
||||
|
||||
c = m_text.at(idx);
|
||||
|
||||
if (c == '\t') {
|
||||
int toff = ts - (column % ts);
|
||||
cwidth = toff * impl->m_spaceWidth;
|
||||
column += toff - 1;
|
||||
} else if (c == ' ') {
|
||||
cwidth = impl->m_spaceWidth;
|
||||
} else if (idx < m_composited.count()) {
|
||||
int nfmt = m_composited[idx];
|
||||
|
||||
if (fmt != nfmt) {
|
||||
m_doc->impl()->tunePainter(p, nfmt);
|
||||
fmt = nfmt;
|
||||
}
|
||||
|
||||
// make sure bold/italicized/.. chars are taken into
|
||||
// account...
|
||||
cwidth = p->fontMetrics().horizontalAdvance(c);
|
||||
} else {
|
||||
// char uses default font...
|
||||
cwidth = impl->m_fontMetrics.horizontalAdvance(c);
|
||||
}
|
||||
|
||||
if ((xpos + cwidth) > xOffset) {
|
||||
// MUST be done after setting the proper chararcter width!
|
||||
if (wrapped && (wrap < m_frontiers.count()) &&
|
||||
(idx >= m_frontiers.at(wrap).first)) {
|
||||
if (sellen || leftSel) {
|
||||
p->fillRect(xpos, ypos, maxWidth - xpos,
|
||||
impl->m_lineSpacing, pal.highlight());
|
||||
}
|
||||
|
||||
++wrap;
|
||||
xpos = indent;
|
||||
ypos += impl->m_lineSpacing;
|
||||
|
||||
if (sellen || leftSel) {
|
||||
p->fillRect(impl->m_leftMargin, ypos,
|
||||
xpos - impl->m_leftMargin +
|
||||
(leftSel ? 0 : cwidth),
|
||||
impl->m_lineSpacing, pal.highlight());
|
||||
}
|
||||
|
||||
} else {
|
||||
if (sellen) {
|
||||
p->fillRect(xpos, ypos, cwidth, impl->m_lineSpacing,
|
||||
pal.highlight());
|
||||
}
|
||||
}
|
||||
|
||||
const int baseline = ypos + impl->m_ascent;
|
||||
|
||||
if (!c.isSpace()) {
|
||||
if (leading)
|
||||
indent = xpos;
|
||||
|
||||
leading = false;
|
||||
|
||||
if (fullSel || sellen)
|
||||
p->setPen(pal.highlightedText().color());
|
||||
|
||||
p->drawText(xpos, baseline, QString(c));
|
||||
} else if (((c == ' ') && ((leading && showLeading) ||
|
||||
((idx > last) && showTrailing))) ||
|
||||
((c == '\t') && showTabs)) {
|
||||
// p->drawText(xpos - m_spaceSignOffset, ypos +
|
||||
// QDocumentPrivate::m_ascent, QChar(0x231E));
|
||||
|
||||
p->translate(xpos - m_spaceSignOffset,
|
||||
ypos + impl->m_ascent);
|
||||
p->drawPoints(m_spaceSign,
|
||||
sizeof(m_spaceSign) / sizeof(QPoint));
|
||||
p->translate(m_spaceSignOffset - xpos,
|
||||
-ypos - impl->m_ascent);
|
||||
}
|
||||
|
||||
for (int cidx = 0; cidx < cursor.count(); ++cidx) {
|
||||
if (cursor[cidx] == idx)
|
||||
p->drawLine(xpos, ypos, xpos,
|
||||
ypos + impl->m_lineSpacing);
|
||||
}
|
||||
|
||||
if (idx < m_composited.count()) {
|
||||
QFormat format = m_doc->impl()->m_formatScheme->format(
|
||||
m_composited[idx]);
|
||||
|
||||
// qDebug("underline pos : %i",
|
||||
// p->fontMetrics().underlinePos());
|
||||
|
||||
const int ydo = baseline + p->fontMetrics().underlinePos();
|
||||
const int yin = baseline - p->fontMetrics().strikeOutPos();
|
||||
const int yup = baseline - p->fontMetrics().overlinePos();
|
||||
|
||||
if (format.overline) {
|
||||
p->drawLine(xpos, yup, xpos + cwidth, yup);
|
||||
}
|
||||
|
||||
if (format.strikeout) {
|
||||
p->drawLine(xpos, yin, xpos + cwidth, yin);
|
||||
}
|
||||
|
||||
if (format.underline) {
|
||||
p->drawLine(xpos, ydo, xpos + cwidth, ydo);
|
||||
}
|
||||
|
||||
if (format.waveUnderline) {
|
||||
QPen oldpen = p->pen();
|
||||
p->setPen(QColor(255, 0, 0));
|
||||
|
||||
p->drawLine(xpos, ydo, xpos + cwidth / 2,
|
||||
ypos + impl->m_lineSpacing - 1);
|
||||
|
||||
p->drawLine(xpos + cwidth / 2,
|
||||
ypos + impl->m_lineSpacing - 1,
|
||||
xpos + cwidth, ydo);
|
||||
|
||||
p->setPen(oldpen);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (wrapped && (wrap < m_frontiers.count()) &&
|
||||
(idx >= m_frontiers.at(wrap).first)) {
|
||||
++wrap;
|
||||
xpos = indent;
|
||||
ypos += impl->m_lineSpacing;
|
||||
}
|
||||
|
||||
if (!c.isSpace()) {
|
||||
if (leading)
|
||||
indent = xpos;
|
||||
|
||||
leading = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (sellen)
|
||||
leftSel = !(--sellen);
|
||||
else
|
||||
leftSel = false;
|
||||
|
||||
if (leftSel) {
|
||||
p->setPen(pal.text().color());
|
||||
fmt = 0;
|
||||
}
|
||||
|
||||
xpos += cwidth;
|
||||
++column;
|
||||
++idx;
|
||||
|
||||
if (!wrapped && xpos > maxWidth)
|
||||
break;
|
||||
}
|
||||
|
||||
// ensure drawing of cursor at EOL
|
||||
for (int cidx = 0; cidx < cursor.count(); ++cidx) {
|
||||
if (cursor[cidx] == idx)
|
||||
p->drawLine(xpos, ypos, xpos, ypos + impl->m_lineSpacing);
|
||||
}
|
||||
|
||||
if (wrapped && unbounded)
|
||||
p->fillRect(xpos, ypos, maxWidth - xpos, impl->m_lineSpacing,
|
||||
pal.highlight());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4524,18 +4310,28 @@ T *getStaticDefault() {
|
|||
QFormatScheme *QDocumentPrivate::m_defaultFormatScheme =
|
||||
getStaticDefault<QFormatScheme>();
|
||||
|
||||
QFont QDocumentPrivate::m_defaultFont;
|
||||
int QDocumentPrivate::m_defaultTabStop = 4;
|
||||
QDocument::LineEnding QDocumentPrivate::m_defaultLineEnding =
|
||||
QDocument::LineEnding::Conservative;
|
||||
QDocument::WhiteSpaceMode QDocumentPrivate::m_defaultShowSpaces =
|
||||
QDocument::ShowNone;
|
||||
|
||||
QList<QDocumentPrivate *> QDocumentPrivate::m_documents;
|
||||
|
||||
QDocumentPrivate::QDocumentPrivate(QDocument *d)
|
||||
: m_doc(d), m_editCursor(0), m_lastGroupId(-1), m_constrained(false),
|
||||
m_width(0), m_height(0), m_tabStop(4), m_formatScheme(0),
|
||||
m_language(nullptr), m_maxMarksPerLine(0), _nix(0), _dos(0), _mac(0),
|
||||
m_lineEnding(QDocument::Conservative), m_wrapMargin(15), m_font(),
|
||||
m_fontMetrics(m_font), m_leftMargin(5),
|
||||
m_showSpaces(QDocument::ShowNone) {
|
||||
setFont(qApp->font());
|
||||
m_width(0), m_height(0), m_tabStop(m_defaultTabStop), m_font(),
|
||||
m_fontMetrics(m_font), m_leftMargin(5), m_showSpaces(m_defaultShowSpaces),
|
||||
m_wrapMargin(15), m_formatScheme(nullptr), m_language(nullptr),
|
||||
m_maxMarksPerLine(0), _nix(0), _dos(0), _mac(0),
|
||||
m_lineEnding(m_defaultLineEnding) {
|
||||
setFont(m_defaultFont);
|
||||
m_documents << this;
|
||||
updateFormatCache();
|
||||
|
||||
if (d) {
|
||||
updateFormatCache();
|
||||
}
|
||||
}
|
||||
|
||||
QDocumentPrivate::~QDocumentPrivate() {
|
||||
|
@ -4961,6 +4757,8 @@ void QDocumentPrivate::setWidth() {
|
|||
|
||||
if (first != -1)
|
||||
first = i;
|
||||
|
||||
qApp->processEvents();
|
||||
}
|
||||
|
||||
if (first != -1)
|
||||
|
@ -4984,6 +4782,8 @@ void QDocumentPrivate::setWidth() {
|
|||
m_largest.clear();
|
||||
m_largest << qMakePair(l, w);
|
||||
}
|
||||
|
||||
qApp->processEvents();
|
||||
}
|
||||
|
||||
if (m_width != oldWidth)
|
||||
|
@ -4991,8 +4791,6 @@ void QDocumentPrivate::setWidth() {
|
|||
}
|
||||
}
|
||||
|
||||
static const int widthCacheSize = 5;
|
||||
|
||||
void QDocumentPrivate::adjustWidth(int line) {
|
||||
if (line < 0 || line >= m_lines.count())
|
||||
return;
|
||||
|
@ -5126,9 +4924,6 @@ void QDocumentPrivate::updateFormatCache() {
|
|||
m_fonts << f;
|
||||
}
|
||||
|
||||
// foreach ( QDocumentPrivate *d, m_documents )
|
||||
// d->emitFormatsChanged();
|
||||
|
||||
emit m_doc->formatsChanged();
|
||||
}
|
||||
|
||||
|
|
|
@ -186,6 +186,8 @@ public:
|
|||
QFormatScheme *formatScheme() const;
|
||||
void setFormatScheme(QFormatScheme *f);
|
||||
|
||||
int lineSpacing() const;
|
||||
|
||||
int getNextGroupId();
|
||||
void releaseGroupId(int groupId);
|
||||
void clearMatches(int groupId);
|
||||
|
@ -254,6 +256,8 @@ signals:
|
|||
|
||||
void lineEndingChanged(int lineEnding);
|
||||
|
||||
void fontChanged(const QFont &font);
|
||||
|
||||
private:
|
||||
QString m_leftOver;
|
||||
QDocumentPrivate *m_impl;
|
||||
|
|
|
@ -54,6 +54,7 @@ Q_DECLARE_TYPEINFO(QDocumentSelection, Q_PRIMITIVE_TYPE);
|
|||
class QCE_EXPORT QDocumentPrivate {
|
||||
friend class QEditConfig;
|
||||
|
||||
friend class QEditor;
|
||||
friend class QDocument;
|
||||
friend class QDocumentCommand;
|
||||
friend class QDocumentLineHandle;
|
||||
|
@ -195,6 +196,11 @@ private:
|
|||
int m_leading;
|
||||
int m_wrapMargin;
|
||||
|
||||
static QFont m_defaultFont;
|
||||
static int m_defaultTabStop;
|
||||
static QDocument::LineEnding m_defaultLineEnding;
|
||||
static QDocument::WhiteSpaceMode m_defaultShowSpaces;
|
||||
|
||||
QFormatScheme *m_formatScheme;
|
||||
QLanguageDefinition *m_language;
|
||||
static QFormatScheme *m_defaultFormatScheme;
|
||||
|
|
|
@ -159,14 +159,16 @@ void QDocumentCommand::insertText(int line, int pos, const QString &s,
|
|||
|
||||
if (!sfmtID.isEmpty()) {
|
||||
auto fmt = m_doc->formatScheme();
|
||||
auto id = fmt->id(sfmtID);
|
||||
if (id) {
|
||||
QFormatRange range;
|
||||
range.format = id;
|
||||
range.offset = pos;
|
||||
range.length = s.length();
|
||||
if (fmt) {
|
||||
auto id = fmt->id(sfmtID);
|
||||
if (id) {
|
||||
QFormatRange over;
|
||||
over.format = id;
|
||||
over.offset = pos;
|
||||
over.length = s.length();
|
||||
|
||||
h->addOverlay(range);
|
||||
h->addOverlay(over);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -514,7 +516,17 @@ QDocumentInsertCommand::QDocumentInsertCommand(int l, int offset,
|
|||
m_data.endOffset = lines.count() ? lines.last().length() : -1;
|
||||
|
||||
for (auto &s : lines) {
|
||||
m_data.handles << new QDocumentLineHandle(s, m_doc);
|
||||
auto lh = new QDocumentLineHandle(s, m_doc);
|
||||
QFormatRange over;
|
||||
auto fmt = m_doc->formatScheme();
|
||||
auto id = fmt->id(sfmtID);
|
||||
if (id) {
|
||||
over.format = id;
|
||||
over.offset = 0;
|
||||
over.length = s.length();
|
||||
lh->addOverlay(over);
|
||||
}
|
||||
m_data.handles << lh;
|
||||
}
|
||||
|
||||
QDocumentLine bl = m_doc->line(l);
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
#include "qce-config.h"
|
||||
|
||||
#include <QMetaType>
|
||||
|
||||
/*!
|
||||
\file qdocumentcursor.h
|
||||
\brief Definition of the QDocumentCursor class
|
||||
|
@ -181,4 +183,6 @@ private:
|
|||
QDocumentCursorHandle *m_handle;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(QDocumentCursor);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -63,7 +63,7 @@ public:
|
|||
};
|
||||
|
||||
// added by wingsummer
|
||||
[[maybe_unused]] static QStringList getEncodings() {
|
||||
Q_DECL_UNUSED static QStringList getEncodings() {
|
||||
static QStringList encodings;
|
||||
|
||||
if (encodings.isEmpty()) {
|
||||
|
@ -91,8 +91,8 @@ public:
|
|||
return encodings;
|
||||
}
|
||||
|
||||
[[maybe_unused]] static QString convertString(const QString &encoding,
|
||||
const QByteArray &data) {
|
||||
Q_DECL_UNUSED static QString convertString(const QString &encoding,
|
||||
const QByteArray &data) {
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
auto enc = QStringConverter::encodingForName(encoding.toUtf8());
|
||||
if (enc) {
|
||||
|
@ -113,8 +113,8 @@ public:
|
|||
#endif
|
||||
}
|
||||
|
||||
[[maybe_unused]] static QByteArray convertByteArray(const QString &encoding,
|
||||
const QString &data) {
|
||||
Q_DECL_UNUSED static QByteArray convertByteArray(const QString &encoding,
|
||||
const QString &data) {
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
auto enc = QStringConverter::encodingForName(encoding.toUtf8());
|
||||
if (enc) {
|
||||
|
|
|
@ -222,7 +222,7 @@ QPanelLayout *QCodeEdit::panelLayout() const { return m_layout; }
|
|||
QAction *QCodeEdit::addPanel(QPanel *panel, Position pos, bool _add) {
|
||||
panel->attach(m_editor);
|
||||
|
||||
QAction *a = new QAction(panel->type(), m_editor);
|
||||
QAction *a = new QAction(panel->name(), m_editor);
|
||||
a->setCheckable(true);
|
||||
a->setChecked(panel->defaultVisibility());
|
||||
|
||||
|
|
|
@ -261,7 +261,7 @@ QReliableFileWatch *QEditor::watcher() {
|
|||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int QEditor::m_defaultFlags = QEditor::AutoIndent | QEditor::AdjustIndent;
|
||||
QString QEditor::m_defaultCodecName = 0;
|
||||
QString QEditor::m_defaultCodecName = {};
|
||||
|
||||
/*!
|
||||
\return The default flags set to every QEditor upon construction
|
||||
|
@ -302,6 +302,53 @@ void QEditor::setDefaultFlags(int flags) {
|
|||
}
|
||||
}
|
||||
|
||||
QFont QEditor::defaultFont() { return QDocumentPrivate::m_defaultFont; }
|
||||
|
||||
void QEditor::setDefaultFont(const QFont &font) {
|
||||
QDocumentPrivate::m_defaultFont = font;
|
||||
for (auto &e : m_editors) {
|
||||
auto doc = e->document();
|
||||
doc->setFont(font);
|
||||
}
|
||||
}
|
||||
|
||||
int QEditor::defaultTabStop() { return QDocumentPrivate::m_defaultTabStop; }
|
||||
|
||||
void QEditor::setDefaultTabStop(int tabstop) {
|
||||
if (tabstop <= 0) {
|
||||
return;
|
||||
}
|
||||
QDocumentPrivate::m_defaultTabStop = tabstop;
|
||||
for (auto &e : m_editors) {
|
||||
auto doc = e->document();
|
||||
doc->setTabStop(tabstop);
|
||||
}
|
||||
}
|
||||
|
||||
QDocument::LineEnding QEditor::defaultLineEnding() {
|
||||
return QDocumentPrivate::m_defaultLineEnding;
|
||||
}
|
||||
|
||||
void QEditor::setDefaultLineEnding(QDocument::LineEnding le) {
|
||||
QDocumentPrivate::m_defaultLineEnding = le;
|
||||
for (auto &e : m_editors) {
|
||||
auto doc = e->document();
|
||||
doc->setLineEnding(le);
|
||||
}
|
||||
}
|
||||
|
||||
QDocument::WhiteSpaceMode QEditor::defaultShowSpaces() {
|
||||
return QDocumentPrivate::m_defaultShowSpaces;
|
||||
}
|
||||
|
||||
void QEditor::setDefaultShowSpaces(QDocument::WhiteSpaceMode y) {
|
||||
QDocumentPrivate::m_defaultShowSpaces = y;
|
||||
for (auto &e : m_editors) {
|
||||
auto doc = e->document();
|
||||
doc->setShowSpaces(y);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return The default text codec used to load and save document contents
|
||||
|
||||
|
@ -343,10 +390,10 @@ void QEditor::setDefaultCodec(const QString &name, int update) {
|
|||
\note Creates builtin menus/actions
|
||||
*/
|
||||
QEditor::QEditor(QWidget *p)
|
||||
: QAbstractScrollArea(p), pMenu(0), m_lineEndingsMenu(0),
|
||||
m_lineEndingsActions(0), m_bindingsMenu(0), aDefaultBinding(0),
|
||||
m_bindingsActions(0), m_doc(0), m_codec(m_defaultCodecName),
|
||||
m_definition(0), m_curPlaceHolder(-1), m_state(defaultFlags()) {
|
||||
: QAbstractScrollArea(p), pMenu(nullptr), m_bindingsMenu(nullptr),
|
||||
aDefaultBinding(nullptr), m_bindingsActions(nullptr), m_doc(nullptr),
|
||||
m_codec(m_defaultCodecName), m_definition(nullptr), m_curPlaceHolder(-1),
|
||||
m_state(defaultFlags()) {
|
||||
m_editors << this;
|
||||
|
||||
m_saveState = Undefined;
|
||||
|
@ -359,10 +406,10 @@ QEditor::QEditor(QWidget *p)
|
|||
\param actions Whether builtin actions and menus should be created
|
||||
*/
|
||||
QEditor::QEditor(bool actions, QWidget *p)
|
||||
: QAbstractScrollArea(p), pMenu(0), m_lineEndingsMenu(0),
|
||||
m_lineEndingsActions(0), m_bindingsMenu(0), aDefaultBinding(0),
|
||||
m_bindingsActions(0), m_doc(0), m_codec(m_defaultCodecName),
|
||||
m_definition(0), m_curPlaceHolder(-1), m_state(defaultFlags()) {
|
||||
: QAbstractScrollArea(p), pMenu(nullptr), m_bindingsMenu(nullptr),
|
||||
aDefaultBinding(nullptr), m_bindingsActions(nullptr), m_doc(nullptr),
|
||||
m_codec(m_defaultCodecName), m_definition(nullptr), m_curPlaceHolder(-1),
|
||||
m_state(defaultFlags()) {
|
||||
m_editors << this;
|
||||
|
||||
m_saveState = Undefined;
|
||||
|
@ -370,46 +417,6 @@ QEditor::QEditor(bool actions, QWidget *p)
|
|||
init(actions);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief ctor
|
||||
\param s file to load
|
||||
|
||||
\note Creates builtin menus/actions
|
||||
*/
|
||||
QEditor::QEditor(const QString &s, QWidget *p)
|
||||
: QAbstractScrollArea(p), pMenu(0), m_lineEndingsMenu(0),
|
||||
m_lineEndingsActions(0), m_bindingsMenu(0), aDefaultBinding(0),
|
||||
m_bindingsActions(0), m_doc(0), m_codec(m_defaultCodecName),
|
||||
m_definition(0), m_curPlaceHolder(-1), m_state(defaultFlags()) {
|
||||
m_editors << this;
|
||||
|
||||
m_saveState = Undefined;
|
||||
|
||||
init();
|
||||
|
||||
setText(s);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief ctor
|
||||
\param s file to load
|
||||
\param actions Whether builtin actions and menus should be created
|
||||
\note Creates builtin menus/action
|
||||
*/
|
||||
QEditor::QEditor(const QString &s, bool actions, QWidget *p)
|
||||
: QAbstractScrollArea(p), pMenu(0), m_lineEndingsMenu(0),
|
||||
m_lineEndingsActions(0), m_bindingsMenu(0), aDefaultBinding(0),
|
||||
m_bindingsActions(0), m_doc(0), m_codec(m_defaultCodecName),
|
||||
m_definition(0), m_curPlaceHolder(-1), m_state(defaultFlags()) {
|
||||
m_editors << this;
|
||||
|
||||
m_saveState = Undefined;
|
||||
|
||||
init(actions);
|
||||
|
||||
setText(s);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief dtor
|
||||
*/
|
||||
|
@ -477,9 +484,6 @@ void QEditor::init(bool actions) {
|
|||
|
||||
connect(m_doc, &QDocument::markChanged, this, &QEditor::emitMarkChanged);
|
||||
|
||||
connect(m_doc, &QDocument::lineEndingChanged, this,
|
||||
&QEditor::lineEndingChanged);
|
||||
|
||||
m_cursor = QDocumentCursor(m_doc);
|
||||
m_cursor.setAutoUpdated(true);
|
||||
|
||||
|
@ -487,9 +491,9 @@ void QEditor::init(bool actions) {
|
|||
m_bindings << m_defaultBinding;
|
||||
}
|
||||
|
||||
if (actions) {
|
||||
pMenu = new QMenu;
|
||||
pMenu = new QMenu;
|
||||
|
||||
if (actions) {
|
||||
QAction *a, *sep;
|
||||
|
||||
a = new QAction(QIcon(":/qeditor/undo.png"), tr("&Undo"), this);
|
||||
|
@ -665,32 +669,6 @@ void QEditor::init(bool actions) {
|
|||
sep->setSeparator(true);
|
||||
addAction(sep, QString());
|
||||
|
||||
m_lineEndingsMenu = new QMenu(tr("Line endings"), this);
|
||||
m_lineEndingsActions = new QActionGroup(m_lineEndingsMenu);
|
||||
m_lineEndingsActions->setExclusive(true);
|
||||
|
||||
connect(m_lineEndingsActions, &QActionGroup::triggered, this,
|
||||
&QEditor::lineEndingSelected);
|
||||
|
||||
m_lineEndingsActions->addAction(tr("Conservative"))
|
||||
->setData("conservative");
|
||||
m_lineEndingsActions->addAction(tr("Local"))->setData("local");
|
||||
m_lineEndingsActions->addAction(tr("Unix/Linux"))->setData("unix");
|
||||
m_lineEndingsActions->addAction(tr("Dos/Windows"))->setData("dos");
|
||||
m_lineEndingsActions->addAction(tr("Old Mac"))->setData("mac");
|
||||
|
||||
QList<QAction *> lle = m_lineEndingsActions->actions();
|
||||
|
||||
for (auto &a : lle) {
|
||||
a->setCheckable(true);
|
||||
m_lineEndingsMenu->addAction(a);
|
||||
}
|
||||
|
||||
lle.at(0)->setChecked(true);
|
||||
|
||||
m_lineEndingsMenu->menuAction()->setObjectName("lineEndings");
|
||||
addAction(m_lineEndingsMenu->menuAction(), "&Edit", "");
|
||||
|
||||
/*
|
||||
sep = new QAction(this);
|
||||
sep->setSeparator(true);
|
||||
|
@ -1234,34 +1212,6 @@ bool QEditor::load(const QString &file) {
|
|||
|
||||
// qDebug("checksum = %i", m_lastFileState.checksum);
|
||||
|
||||
if (m_lineEndingsActions) {
|
||||
// TODO : update Conservative to report original line endings
|
||||
static const QRegularExpression rx(" \\[\\w+\\]");
|
||||
QAction *a = m_lineEndingsActions->actions().at(0);
|
||||
|
||||
if (a) {
|
||||
QDocument::LineEnding le = m_doc->originalLineEnding();
|
||||
|
||||
QString det, txt = a->text();
|
||||
txt.remove(rx);
|
||||
|
||||
if (le == QDocument::Windows)
|
||||
det = tr("Windows");
|
||||
else if (le == QDocument::OldMac)
|
||||
det = tr("Old Mac");
|
||||
else if (le == QDocument::Unix)
|
||||
det = tr("Unix");
|
||||
|
||||
if (det.size()) {
|
||||
txt += " [";
|
||||
txt += det;
|
||||
txt += ']';
|
||||
}
|
||||
|
||||
a->setText(txt);
|
||||
}
|
||||
}
|
||||
|
||||
setFileName(file);
|
||||
|
||||
emit loaded(this, file);
|
||||
|
@ -1277,9 +1227,15 @@ QDocument *QEditor::document() const { return m_doc; }
|
|||
\internal
|
||||
*/
|
||||
void QEditor::setDocument(QDocument *d) {
|
||||
Q_UNUSED(d)
|
||||
if (d == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
qWarning("QEditor::setDocument() is not working yet...");
|
||||
m_doc = d;
|
||||
documentWidthChanged(m_doc->width());
|
||||
documentHeightChanged(m_doc->height());
|
||||
setFileName(QString());
|
||||
m_cursor = *m_doc->editCursor();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -1291,16 +1247,24 @@ QString QEditor::codecName() const { return m_codec; }
|
|||
\brief Set the text codec to use for load/save operations
|
||||
*/
|
||||
void QEditor::setCodec(const QString &c) {
|
||||
if (c == m_codec || !QCE::getEncodings().contains(c))
|
||||
if (c == m_codec)
|
||||
return;
|
||||
|
||||
m_codec = c;
|
||||
if (c == QStringLiteral("ISO-8859-1")) {
|
||||
m_codec = QStringLiteral("ASCII");
|
||||
} else {
|
||||
if (!QCE::getEncodings().contains(c)) {
|
||||
return;
|
||||
}
|
||||
m_codec = c;
|
||||
}
|
||||
|
||||
// TODO : reload file?
|
||||
if (fileName().size() && QFile::exists(fileName())) {
|
||||
if (!fileName().isEmpty() && QFile::exists(fileName())) {
|
||||
if (!isContentModified()) {
|
||||
load(fileName());
|
||||
}
|
||||
} else {
|
||||
emit needLoading();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1460,45 +1424,6 @@ void QEditor::bindingSelected(QAction *a) {
|
|||
updateMicroFocus();
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
void QEditor::lineEndingSelected(QAction *a) {
|
||||
a = m_lineEndingsActions->checkedAction();
|
||||
|
||||
if (!a)
|
||||
return;
|
||||
|
||||
QString le = a->data().toString();
|
||||
|
||||
if (le == "conservative")
|
||||
m_doc->setLineEnding(QDocument::Conservative);
|
||||
else if (le == "local")
|
||||
m_doc->setLineEnding(QDocument::Local);
|
||||
else if (le == "unix")
|
||||
m_doc->setLineEnding(QDocument::Unix);
|
||||
else if (le == "dos")
|
||||
m_doc->setLineEnding(QDocument::Windows);
|
||||
else if (le == "mac")
|
||||
m_doc->setLineEnding(QDocument::OldMac);
|
||||
|
||||
updateMicroFocus();
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
void QEditor::lineEndingChanged(int lineEnding) {
|
||||
if (!m_lineEndingsActions)
|
||||
return;
|
||||
|
||||
QAction *a = m_lineEndingsActions->checkedAction(),
|
||||
*n = m_lineEndingsActions->actions().at(lineEnding);
|
||||
|
||||
if (a != n)
|
||||
n->setChecked(true);
|
||||
}
|
||||
|
||||
/*!
|
||||
\return the current cursor
|
||||
*/
|
||||
|
@ -1690,6 +1615,13 @@ void QEditor::setPlaceHolder(int i) {
|
|||
|
||||
void QEditor::setUndoRedoEnabled(bool b) { m_undoRedoEnabled = b; }
|
||||
|
||||
void QEditor::setCursorMirrorEnabled(bool b) {
|
||||
m_cursorMirrorEnabled = b;
|
||||
if (!b) {
|
||||
clearCursorMirrors();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Move to next placeholder
|
||||
|
||||
|
@ -1841,6 +1773,10 @@ void QEditor::emitCursorPositionChanged() {
|
|||
\brief Undo the last editing operation, if any on the stack
|
||||
*/
|
||||
void QEditor::undo() {
|
||||
if (flag(ReadOnly)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_doc && m_undoRedoEnabled) {
|
||||
if (m_definition)
|
||||
m_definition->clearMatches(m_doc);
|
||||
|
@ -1858,6 +1794,10 @@ void QEditor::undo() {
|
|||
\brief Redo the last undone editing operation, if any on the stack
|
||||
*/
|
||||
void QEditor::redo() {
|
||||
if (flag(ReadOnly)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_doc && m_undoRedoEnabled) {
|
||||
if (m_definition)
|
||||
m_definition->clearMatches(m_doc);
|
||||
|
@ -1875,6 +1815,10 @@ void QEditor::redo() {
|
|||
\brief Cut the selected text, if any
|
||||
*/
|
||||
void QEditor::cut() {
|
||||
if (flag(ReadOnly)) {
|
||||
return;
|
||||
}
|
||||
|
||||
copy();
|
||||
|
||||
bool macro = m_mirrors.count();
|
||||
|
@ -1921,12 +1865,21 @@ void QEditor::copy() {
|
|||
\note May paste column selections from other QCE editors
|
||||
*/
|
||||
void QEditor::paste() {
|
||||
if (flag(ReadOnly)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QMimeData *d = QApplication::clipboard()->mimeData();
|
||||
|
||||
if (d)
|
||||
insertFromMimeData(d);
|
||||
}
|
||||
|
||||
void QEditor::clear() {
|
||||
m_doc->clear();
|
||||
m_cursor = *m_doc->editCursor();
|
||||
}
|
||||
|
||||
static void insert(const QDocumentCursor &cur, const QString &txt) {
|
||||
QDocumentCursor c(cur);
|
||||
c.setSilent(true);
|
||||
|
@ -1953,6 +1906,9 @@ static void removeFromStart(const QDocumentCursor &cur, const QString &txt) {
|
|||
*/
|
||||
void QEditor::indentSelection() {
|
||||
// TODO : respect tab stops in case of screwed up indent (correct it?)
|
||||
if (flag(ReadOnly)) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString txt =
|
||||
flag(ReplaceTabs) ? QString(m_doc->tabStop(), ' ') : QString("\t");
|
||||
|
@ -1994,6 +1950,10 @@ void QEditor::indentSelection() {
|
|||
\brief Unindent the selection
|
||||
*/
|
||||
void QEditor::unindentSelection() {
|
||||
if (flag(ReadOnly)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_cursor.line().firstChar())
|
||||
return;
|
||||
|
||||
|
@ -2070,8 +2030,8 @@ void QEditor::commentSelection() {
|
|||
}
|
||||
|
||||
/*!
|
||||
\brief Uncomment the selection (or current line), provided it has been
|
||||
commented with single line comments
|
||||
\brief Uncomment the selection (or current line), provided it has
|
||||
been commented with single line comments
|
||||
*/
|
||||
void QEditor::uncommentSelection() {
|
||||
if (!m_definition)
|
||||
|
@ -2135,8 +2095,9 @@ bool QEditor::event(QEvent *e) {
|
|||
qMax(0, 1 + (m_doc->height() - viewport()->height()) /
|
||||
m_doc->fontMetrics().lineSpacing()));
|
||||
|
||||
if (e->type() == QEvent::Resize && flag(LineWrap)) {
|
||||
// qDebug("resize adjust (1) : wrapping to %i", viewport()->width());
|
||||
if (e->type() == QEvent::Resize && flag(LineWrap) && m_doc) {
|
||||
// qDebug("resize adjust (1) : wrapping to %i",
|
||||
// viewport()->width());
|
||||
m_doc->setWidthConstraint(wrapWidth());
|
||||
ensureCursorVisible();
|
||||
}
|
||||
|
@ -2293,6 +2254,116 @@ bool QEditor::protectedCursor(const QDocumentCursor &c) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
void QEditor::createSimpleBasicContextMenu(bool shortcut, bool extTool) {
|
||||
if (pMenu == nullptr) {
|
||||
pMenu = new QMenu(this);
|
||||
}
|
||||
|
||||
QAction *a = nullptr, *sep = nullptr;
|
||||
|
||||
if (m_undoRedoEnabled) {
|
||||
a = new QAction(QIcon(":/qeditor/undo.png"), tr("&Undo"), this);
|
||||
a->setObjectName("undo");
|
||||
if (shortcut)
|
||||
Q_SHORTCUT(a, "Ctrl+Z", "Edit");
|
||||
a->setEnabled(false);
|
||||
connect(this, &QEditor::undoAvailable, a, &QAction::setEnabled);
|
||||
connect(a, &QAction::triggered, this, &QEditor::undo);
|
||||
|
||||
addAction(a, "&Edit", "Edit");
|
||||
|
||||
a = new QAction(QIcon(":/qeditor/redo.png"), tr("&Redo"), this);
|
||||
a->setObjectName("redo");
|
||||
if (shortcut)
|
||||
Q_SHORTCUT(a, "Ctrl+Y", "Edit");
|
||||
a->setEnabled(false);
|
||||
connect(this, SIGNAL(redoAvailable(bool)), a, SLOT(setEnabled(bool)));
|
||||
connect(a, SIGNAL(triggered()), this, SLOT(redo()));
|
||||
|
||||
addAction(a, "&Edit", "Edit");
|
||||
}
|
||||
|
||||
sep = new QAction(this);
|
||||
sep->setSeparator(true);
|
||||
addAction(sep, "&Edit", "Edit");
|
||||
|
||||
if (!flag(ReadOnly)) {
|
||||
a = new QAction(QIcon(":/qeditor/cut.png"), tr("Cu&t"), this);
|
||||
a->setObjectName("cut");
|
||||
if (shortcut)
|
||||
Q_SHORTCUT(a, "Ctrl+X", "Edit");
|
||||
a->setEnabled(false);
|
||||
connect(this, SIGNAL(copyAvailable(bool)), a, SLOT(setEnabled(bool)));
|
||||
connect(a, SIGNAL(triggered()), this, SLOT(cut()));
|
||||
|
||||
addAction(a, "&Edit", "Edit");
|
||||
}
|
||||
|
||||
a = new QAction(QIcon(":/qeditor/copy.png"), tr("&Copy"), this);
|
||||
a->setObjectName("copy");
|
||||
if (shortcut)
|
||||
Q_SHORTCUT(a, "Ctrl+C", "Edit");
|
||||
a->setEnabled(false);
|
||||
connect(this, SIGNAL(copyAvailable(bool)), a, SLOT(setEnabled(bool)));
|
||||
connect(a, SIGNAL(triggered()), this, SLOT(copy()));
|
||||
|
||||
addAction(a, "&Edit", "Edit");
|
||||
|
||||
if (!flag(ReadOnly)) {
|
||||
a = new QAction(QIcon(":/qeditor/paste.png"), tr("&Paste"), this);
|
||||
a->setObjectName("paste");
|
||||
if (shortcut)
|
||||
Q_SHORTCUT(a, "Ctrl+V", "Edit");
|
||||
connect(QApplication::clipboard(), SIGNAL(dataChanged()), this,
|
||||
SLOT(checkClipboard()));
|
||||
|
||||
connect(a, SIGNAL(triggered()), this, SLOT(paste()));
|
||||
|
||||
addAction(a, "&Edit", "Edit");
|
||||
}
|
||||
|
||||
if (extTool) {
|
||||
sep = new QAction(this);
|
||||
sep->setSeparator(true);
|
||||
addAction(sep, QString());
|
||||
|
||||
a = new QAction(QIcon(":/qeditor/find.png"), tr("&Find"), this);
|
||||
a->setObjectName("find");
|
||||
if (shortcut)
|
||||
Q_SHORTCUT(a, "Ctrl+F", "Search");
|
||||
connect(a, SIGNAL(triggered()), this, SLOT(find()));
|
||||
|
||||
addAction(a, "&Search", "Search");
|
||||
|
||||
a = new QAction(tr("Fin&d next"), pMenu);
|
||||
a->setObjectName("findNext");
|
||||
if (shortcut)
|
||||
Q_SHORTCUT(a, "F3", "Search");
|
||||
connect(a, SIGNAL(triggered()), this, SLOT(findNext()));
|
||||
|
||||
addAction(a, "&Search", "Search");
|
||||
|
||||
a = new QAction(QIcon(":/qeditor/replace.png"), tr("&Replace"), this);
|
||||
a->setObjectName("replace");
|
||||
Q_SHORTCUT(a, "Ctrl+R", "Search");
|
||||
connect(a, SIGNAL(triggered()), this, SLOT(replace()));
|
||||
|
||||
addAction(a, "&Search", "Search");
|
||||
|
||||
sep = new QAction(this);
|
||||
sep->setSeparator(true);
|
||||
addAction(sep, "&Search", "Search");
|
||||
|
||||
a = new QAction(QIcon(":/qeditor/goto.png"), tr("&Goto line..."), this);
|
||||
a->setObjectName("goto");
|
||||
if (shortcut)
|
||||
Q_SHORTCUT(a, "Ctrl+G", "Search");
|
||||
connect(a, SIGNAL(triggered()), this, SLOT(gotoLine()));
|
||||
|
||||
addAction(a, "&Search", "Search");
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
|
@ -2429,10 +2500,12 @@ void QEditor::keyPressEvent(QKeyEvent *e) {
|
|||
bHandled = false;
|
||||
} else {
|
||||
|
||||
// clear matches to avoid offsetting and subsequent remanence of
|
||||
// matches
|
||||
if (m_definition)
|
||||
// clear matches to avoid offsetting and subsequent
|
||||
// remanence of matches
|
||||
if (m_definition) {
|
||||
m_definition->clearMatches(m_doc);
|
||||
viewport()->repaint(); // force repaint in case of crash
|
||||
}
|
||||
|
||||
bool hasPH = m_placeHolders.count() && m_curPlaceHolder != -1;
|
||||
bool macroing = hasPH || m_mirrors.count();
|
||||
|
@ -2466,10 +2539,10 @@ void QEditor::keyPressEvent(QKeyEvent *e) {
|
|||
}
|
||||
|
||||
if (m_mirrors.isEmpty()) {
|
||||
// this signal is NOT emitted when cursor mirrors are used
|
||||
// ON PURPOSE as it is the "standard" entry point for code
|
||||
// completion, which cannot work properly with cursor
|
||||
// mirrors (art least not always and not simply)
|
||||
// this signal is NOT emitted when cursor mirrors are
|
||||
// used ON PURPOSE as it is the "standard" entry point
|
||||
// for code completion, which cannot work properly with
|
||||
// cursor mirrors (art least not always and not simply)
|
||||
if (bHandled)
|
||||
emit textEdited(e);
|
||||
|
||||
|
@ -2486,7 +2559,6 @@ void QEditor::keyPressEvent(QKeyEvent *e) {
|
|||
|
||||
if (!bHandled) {
|
||||
QAbstractScrollArea::keyPressEvent(e);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2849,6 +2921,10 @@ void QEditor::mouseDoubleClickEvent(QMouseEvent *e) {
|
|||
\internal
|
||||
*/
|
||||
void QEditor::dragEnterEvent(QDragEnterEvent *e) {
|
||||
if (flag(ReadOnly)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e && e->mimeData() &&
|
||||
(e->mimeData()->hasFormat("text/plain") ||
|
||||
e->mimeData()->hasFormat("text/html")) &&
|
||||
|
@ -2875,6 +2951,10 @@ void QEditor::dragLeaveEvent(QDragLeaveEvent *) {
|
|||
\internal
|
||||
*/
|
||||
void QEditor::dragMoveEvent(QDragMoveEvent *e) {
|
||||
if (flag(ReadOnly)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e && e->mimeData() &&
|
||||
(e->mimeData()->hasFormat("text/plain") ||
|
||||
e->mimeData()->hasFormat("text/html")) &&
|
||||
|
@ -2908,6 +2988,10 @@ void QEditor::dragMoveEvent(QDragMoveEvent *e) {
|
|||
\internal
|
||||
*/
|
||||
void QEditor::dropEvent(QDropEvent *e) {
|
||||
if (flag(ReadOnly)) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_dragAndDrop = QDocumentCursor();
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
|
@ -3145,8 +3229,8 @@ void QEditor::setFileName(const QString &f) {
|
|||
/*!
|
||||
\brief Set the title of the widget
|
||||
|
||||
Take care of adding a "[*]" prefix so that document changes are visible
|
||||
on title bars.
|
||||
Take care of adding a "[*]" prefix so that document changes are
|
||||
visible on title bars.
|
||||
*/
|
||||
void QEditor::setTitle(const QString &title) {
|
||||
QString s(title);
|
||||
|
@ -3211,8 +3295,8 @@ bool QEditor::moveKeyEvent(QDocumentCursor &cursor, QKeyEvent *e, bool *leave) {
|
|||
|
||||
QDocumentCursor::MoveOperation op = QDocumentCursor::NoMove;
|
||||
#ifdef Q_WS_MAC
|
||||
// There can be only one modifier (+ shift), but we also need to make sure
|
||||
// that we have a "move key" pressed before we reject it.
|
||||
// There can be only one modifier (+ shift), but we also need to make
|
||||
// sure that we have a "move key" pressed before we reject it.
|
||||
bool twoModifiers =
|
||||
((e->modifiers() & (Qt::ControlModifier | Qt::AltModifier)) ==
|
||||
(Qt::ControlModifier | Qt::AltModifier)) ||
|
||||
|
@ -3270,19 +3354,19 @@ bool QEditor::moveKeyEvent(QDocumentCursor &cursor, QKeyEvent *e, bool *leave) {
|
|||
Except for pageup and pagedown, Mac OS X has very different
|
||||
behavior, we don't do it all, but here's the breakdown:
|
||||
|
||||
Shift still works as an anchor, but only one of the other keys
|
||||
can be dow Ctrl (Command), Alt (Option), or Meta (Control).
|
||||
Shift still works as an anchor, but only one of the other
|
||||
keys can be dow Ctrl (Command), Alt (Option), or Meta (Control).
|
||||
|
||||
Command/Control + Left/Right -- Move to left or right of the
|
||||
line
|
||||
+ Up/Down -- Move to top bottom
|
||||
of the file. (Control doesn't move the cursor)
|
||||
+ Up/Down -- Move to top
|
||||
bottom of the file. (Control doesn't move the cursor)
|
||||
|
||||
Option + Left/Right -- Move one word Left/right.
|
||||
+ Up/Down -- Begin/End of Paragraph.
|
||||
|
||||
Home/End Top/Bottom of file. (usually don't move the cursor, but
|
||||
will select)
|
||||
Home/End Top/Bottom of file. (usually don't move the cursor,
|
||||
but will select)
|
||||
*/
|
||||
case Qt::Key_Up:
|
||||
if (twoModifiers) {
|
||||
|
@ -3634,8 +3718,8 @@ void QEditor::preInsert(QDocumentCursor &c, const QString &s) {
|
|||
|
||||
/*
|
||||
It might be possible to improve that part to have a more
|
||||
natural/smarter unindenting by trying to guess the scheme used by the
|
||||
user...
|
||||
natural/smarter unindenting by trying to guess the scheme used by
|
||||
the user...
|
||||
*/
|
||||
|
||||
if (txt.at(firstNS - 1) == '\t') {
|
||||
|
@ -3709,8 +3793,8 @@ void QEditor::insertText(QDocumentCursor &c, const QString &text,
|
|||
l.remove(0, n);
|
||||
|
||||
if (m_definition) {
|
||||
// FIXME ? work on strings to make sure command grouping does
|
||||
// not interfere with cursor state...
|
||||
// FIXME ? work on strings to make sure command grouping
|
||||
// does not interfere with cursor state...
|
||||
indent = m_definition->indent(c);
|
||||
|
||||
if (flag(ReplaceTabs))
|
||||
|
@ -3780,14 +3864,14 @@ void QEditor::setPanelMargins(int l, int t, int r, int b) {
|
|||
}
|
||||
|
||||
/*!
|
||||
\brief Request repaint (using QWidget::update()) for the region occupied
|
||||
by the cursor
|
||||
\brief Request repaint (using QWidget::update()) for the region
|
||||
occupied by the cursor
|
||||
*/
|
||||
void QEditor::repaintCursor() {
|
||||
if (m_mirrors.count())
|
||||
viewport()->update();
|
||||
|
||||
QRect r = QEditor::cursorRect();
|
||||
QRect r = QEditor::cursorRect().adjusted(0, -1, 0, 1);
|
||||
|
||||
if (m_crect != r) {
|
||||
viewport()->update(m_crect.translated(horizontalOffset(), 0));
|
||||
|
@ -3893,14 +3977,15 @@ void QEditor::ensureVisible(const QRect &rect) {
|
|||
This will either return a cursorRect for the current cursor or
|
||||
the selectionRect() if the cursor has a selection.
|
||||
|
||||
The cursor position, which would be the top left corner of the actual
|
||||
rectangle occupied by the cursor can be obtained using
|
||||
The cursor position, which would be the top left corner of the
|
||||
actual rectangle occupied by the cursor can be obtained using
|
||||
QDocumentCursor::documentPosition()
|
||||
|
||||
The behavior of this method may surprise newcomers but it is actually
|
||||
quite sensible as this rectangle is mainly used to specify the update rect of
|
||||
the widget and the whole line needs to be updated to properly update the line
|
||||
background whenever the cursor move from a line to another.
|
||||
The behavior of this method may surprise newcomers but it is
|
||||
actually quite sensible as this rectangle is mainly used to specify the
|
||||
update rect of the widget and the whole line needs to be updated to
|
||||
properly update the line background whenever the cursor move from a line
|
||||
to another.
|
||||
*/
|
||||
QRect QEditor::cursorRect() const {
|
||||
return m_cursor.hasSelection() ? selectionRect()
|
||||
|
@ -3908,14 +3993,15 @@ QRect QEditor::cursorRect() const {
|
|||
}
|
||||
|
||||
/*!
|
||||
\return the rectangle occupied by the selection in viewport coordinates
|
||||
\return the rectangle occupied by the selection in viewport
|
||||
coordinates
|
||||
|
||||
If the current cursor does not have a selection, its cursorRect() is
|
||||
returned.
|
||||
|
||||
The returned rectangle will always be bigger than the actual selection
|
||||
has it is actually the union of all the rectangles occupied by all lines the
|
||||
selection spans over.
|
||||
The returned rectangle will always be bigger than the actual
|
||||
selection has it is actually the union of all the rectangles occupied by
|
||||
all lines the selection spans over.
|
||||
*/
|
||||
QRect QEditor::selectionRect() const {
|
||||
if (!m_cursor.hasSelection())
|
||||
|
@ -3940,7 +4026,8 @@ QRect QEditor::selectionRect() const {
|
|||
\return the rectangle occupied by the given line, in viewport
|
||||
coordinates
|
||||
|
||||
The width of the returned rectangle will always be the viewport width.
|
||||
The width of the returned rectangle will always be the viewport
|
||||
width.
|
||||
*/
|
||||
QRect QEditor::lineRect(int line) const {
|
||||
if (!m_doc)
|
||||
|
@ -3957,8 +4044,8 @@ QRect QEditor::lineRect(int line) const {
|
|||
\overload
|
||||
|
||||
\note This function relies on QDocumentLine::lineNumber() so avoid
|
||||
it whenever possible as it is much slower than providing a line number
|
||||
directly.
|
||||
it whenever possible as it is much slower than providing a line
|
||||
number directly.
|
||||
*/
|
||||
QRect QEditor::lineRect(const QDocumentLine &l) const {
|
||||
// qFatal("bad practice...");
|
||||
|
@ -3977,7 +4064,7 @@ QRect QEditor::lineRect(const QDocumentLine &l) const {
|
|||
\return The line rect of the given cursor
|
||||
*/
|
||||
QRect QEditor::cursorRect(const QDocumentCursor &c) const {
|
||||
return QEditor::lineRect(c.lineNumber()).adjusted(0, -1, 0, 1);
|
||||
return QEditor::lineRect(c.lineNumber());
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -4018,7 +4105,8 @@ static void fixLineEndings(QString &text) {
|
|||
}
|
||||
|
||||
/*!
|
||||
\brief Inserts the content of a QMimeData object at the cursor position
|
||||
\brief Inserts the content of a QMimeData object at the cursor
|
||||
position
|
||||
|
||||
\note Only plain text is supported... \see QMimeData::hasText()
|
||||
*/
|
||||
|
@ -4127,7 +4215,8 @@ void QEditor::clearCursorMirrors() {
|
|||
\brief Add a cursor mirror
|
||||
*/
|
||||
void QEditor::addCursorMirror(const QDocumentCursor &c) {
|
||||
if (c.isNull() || (c == m_cursor) || m_mirrors.contains(c))
|
||||
if (!m_cursorMirrorEnabled || c.isNull() || (c == m_cursor) ||
|
||||
m_mirrors.contains(c))
|
||||
return;
|
||||
|
||||
m_mirrors << c;
|
||||
|
@ -4139,6 +4228,8 @@ void QEditor::addCursorMirror(const QDocumentCursor &c) {
|
|||
|
||||
bool QEditor::undoRedoEnabled() const { return m_undoRedoEnabled; }
|
||||
|
||||
bool QEditor::cursorMirrorEnabled() const { return m_cursorMirrorEnabled; }
|
||||
|
||||
bool QEditor::unindent(const QDocumentCursor &cur) {
|
||||
QDocumentLine beg(cur.line());
|
||||
int r = 0, n = 0, t = m_doc->tabStop();
|
||||
|
@ -4236,7 +4327,8 @@ void QEditor::documentWidthChanged(int newWidth) {
|
|||
\brief Slot called whenever document height changes
|
||||
|
||||
Vertical scrollbar is updated here (maximum is changed
|
||||
and value is modified if needed to ensure that the cursor is visible)
|
||||
and value is modified if needed to ensure that the cursor is
|
||||
visible)
|
||||
*/
|
||||
void QEditor::documentHeightChanged(int newHeight) {
|
||||
if (flag(LineWrap)) {
|
||||
|
|
|
@ -120,10 +120,8 @@ public:
|
|||
QList<QDocumentCursor> mirrors;
|
||||
};
|
||||
|
||||
QEditor(QWidget *p = nullptr);
|
||||
QEditor(bool actions, QWidget *p = nullptr);
|
||||
QEditor(const QString &s, QWidget *p = nullptr);
|
||||
QEditor(const QString &s, bool actions, QWidget *p = nullptr);
|
||||
explicit QEditor(QWidget *p = nullptr);
|
||||
explicit QEditor(bool actions, QWidget *p = nullptr);
|
||||
virtual ~QEditor();
|
||||
|
||||
bool flag(EditFlag) const;
|
||||
|
@ -187,11 +185,25 @@ public:
|
|||
point.y() - verticalOffset());
|
||||
}
|
||||
|
||||
void createSimpleBasicContextMenu(bool shortcut, bool extTool);
|
||||
|
||||
virtual bool protectedCursor(const QDocumentCursor &c) const;
|
||||
|
||||
static int defaultFlags();
|
||||
static void setDefaultFlags(int f);
|
||||
|
||||
static QFont defaultFont();
|
||||
static void setDefaultFont(const QFont &font);
|
||||
|
||||
static int defaultTabStop();
|
||||
static void setDefaultTabStop(int tabstop);
|
||||
|
||||
static QDocument::LineEnding defaultLineEnding();
|
||||
static void setDefaultLineEnding(QDocument::LineEnding le);
|
||||
|
||||
static QDocument::WhiteSpaceMode defaultShowSpaces();
|
||||
static void setDefaultShowSpaces(QDocument::WhiteSpaceMode y);
|
||||
|
||||
static QString defaultCodecName();
|
||||
static void setDefaultCodec(const QString &name, int update);
|
||||
|
||||
|
@ -210,9 +222,11 @@ public slots:
|
|||
void undo();
|
||||
void redo();
|
||||
|
||||
void cut();
|
||||
void copy();
|
||||
void paste();
|
||||
virtual void cut();
|
||||
virtual void copy();
|
||||
virtual void paste();
|
||||
|
||||
void clear();
|
||||
|
||||
void selectAll();
|
||||
|
||||
|
@ -280,6 +294,8 @@ public slots:
|
|||
|
||||
void setUndoRedoEnabled(bool b);
|
||||
|
||||
void setCursorMirrorEnabled(bool b);
|
||||
|
||||
virtual void setFileName(const QString &f);
|
||||
|
||||
public:
|
||||
|
@ -289,6 +305,7 @@ public:
|
|||
|
||||
signals:
|
||||
void loaded(QEditor *e, const QString &s);
|
||||
void needLoading();
|
||||
void saved(QEditor *e, const QString &s);
|
||||
|
||||
void contentModified(bool y);
|
||||
|
@ -389,6 +406,8 @@ public:
|
|||
|
||||
bool undoRedoEnabled() const;
|
||||
|
||||
bool cursorMirrorEnabled() const;
|
||||
|
||||
private:
|
||||
bool unindent(const QDocumentCursor &cur);
|
||||
|
||||
|
@ -403,9 +422,6 @@ protected slots:
|
|||
|
||||
void bindingSelected(QAction *a);
|
||||
|
||||
void lineEndingSelected(QAction *a);
|
||||
void lineEndingChanged(int lineEnding);
|
||||
|
||||
protected:
|
||||
enum SaveState { Undefined, Saving, Saved, Conflict };
|
||||
|
||||
|
@ -417,9 +433,6 @@ protected:
|
|||
QMenu *pMenu;
|
||||
QHash<QString, QAction *> m_actions;
|
||||
|
||||
QMenu *m_lineEndingsMenu;
|
||||
QActionGroup *m_lineEndingsActions;
|
||||
|
||||
QMenu *m_bindingsMenu;
|
||||
QAction *aDefaultBinding;
|
||||
QActionGroup *m_bindingsActions;
|
||||
|
@ -442,6 +455,7 @@ protected:
|
|||
QList<PlaceHolder> m_placeHolders;
|
||||
|
||||
bool m_undoRedoEnabled = true;
|
||||
bool m_cursorMirrorEnabled = true;
|
||||
|
||||
int m_state;
|
||||
bool m_selection;
|
||||
|
|
|
@ -91,9 +91,7 @@ QStringList QLanguageFactory::fileFilters() const {
|
|||
QStringList l;
|
||||
|
||||
foreach (QString lng, m_languages)
|
||||
l << tr("%1 files (*.%2)")
|
||||
.arg(lng)
|
||||
.arg(m_data[lng].extensions.join(" *."));
|
||||
l << tr("%1 files (*.%2)").arg(lng, m_data[lng].extensions.join(" *."));
|
||||
|
||||
l << tr("All files (*)");
|
||||
|
||||
|
@ -240,18 +238,6 @@ QLanguageFactory::languageData(const QString &lang) {
|
|||
return m_data[lang];
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Registers a new completion engine
|
||||
|
||||
\note This engine will NOT be used if there are no language definition
|
||||
for the language it supports...
|
||||
*/
|
||||
void QLanguageFactory::addLanguageDefinition(QLanguageDefinition *l) {
|
||||
Q_UNUSED(l)
|
||||
|
||||
qWarning("New design does not allow this sorry...");
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Registers a new completion engine
|
||||
|
||||
|
|
|
@ -68,7 +68,6 @@ public:
|
|||
|
||||
public slots:
|
||||
void addLanguage(const LangData &d);
|
||||
void addLanguageDefinition(QLanguageDefinition *l);
|
||||
void addCompletionEngine(QCodeCompletionEngine *e);
|
||||
|
||||
virtual void setLanguage(QEditor *e, const QString &f);
|
||||
|
|
|
@ -20,34 +20,24 @@
|
|||
\brief Implementation of the QPanelLayout class.
|
||||
*/
|
||||
|
||||
#include "qdebug.h"
|
||||
#include "qeditor.h"
|
||||
#include "qpanel.h"
|
||||
|
||||
#include <QScrollBar>
|
||||
#include <QWidget>
|
||||
|
||||
#ifdef Q_WS_WIN
|
||||
// panel position fix required on some systems to work around a bug in
|
||||
// QAbstractScrollArea
|
||||
#define _PANEL_POSITION_FIX_
|
||||
#endif
|
||||
|
||||
/*!
|
||||
\class QPanelLayout
|
||||
\brief A specialized layout taking care of panel display
|
||||
|
||||
The panel layout is specialized in several ways :
|
||||
<ul>
|
||||
<li>It only operates on specific widgets (which inherit QPanel)</li>
|
||||
<li>It can only layout widgets in the viewport margins of a QEditor
|
||||
(could work with any QAbstractScrollArea if a single method was made public
|
||||
instead of protected...) so it does not qualify as a "real" layout (contrary
|
||||
to grid/box layouts)</li> <li>It positions widgets on the border of the
|
||||
editor in the same way the Border Layout example does (most of the layout
|
||||
code actually comes from there).</li> <li>It provides
|
||||
serialization/deserialization of its layout structure</li>
|
||||
</ul>
|
||||
The panel layout is specialized in several ways :
|
||||
<ul>
|
||||
<li>It only operates on specific widgets (which inherit QPanel)</li>
|
||||
<li>It can only layout widgets in the viewport margins of a QEditor (could work
|
||||
with any QAbstractScrollArea if a single method was made public instead of
|
||||
protected...) so it does not qualify as a "real" layout (contrary to grid/box
|
||||
layouts)</li> <li>It positions widgets on the border of the editor in the same
|
||||
way the Border Layout example does (most of the layout code actually comes from
|
||||
there).</li> <li>It provides serialization/deserialization of its layout
|
||||
structure</li>
|
||||
</ul>
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -88,8 +78,8 @@ QString QPanelLayout::serialized() const {
|
|||
/*
|
||||
Scheme :
|
||||
|
||||
QPanelLayout::Position '{' comma-separated list of identifiers '}'
|
||||
*/
|
||||
QPanelLayout::Position '{' comma-separated list of identifiers '}'
|
||||
*/
|
||||
|
||||
QHash<int, QString> posMap;
|
||||
|
||||
|
@ -108,11 +98,12 @@ QString QPanelLayout::serialized() const {
|
|||
} else {
|
||||
QString &ref = posMap[position];
|
||||
|
||||
ref.insert(ref.size() - 2, QString(",") + panel->id());
|
||||
ref.insert(ref.length() - 2, QStringLiteral(",") + panel->id());
|
||||
}
|
||||
}
|
||||
|
||||
return QStringList(posMap.values()).join("");
|
||||
auto values = posMap.values();
|
||||
return values.join("");
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -146,7 +137,8 @@ void QPanelLayout::addSerialized(const QString &layout) {
|
|||
}
|
||||
} else if (layout.at(i) == '{') {
|
||||
inList = true;
|
||||
position = Position(layout.mid(last, i - last).toInt());
|
||||
auto pos = layout.mid(last, i - last);
|
||||
position = Position(pos.toInt());
|
||||
|
||||
// qDebug("position : %i [%s]", position,
|
||||
// qPrintable(layout.mid(last, i - last)));
|
||||
|
@ -233,7 +225,12 @@ QLayoutItem *QPanelLayout::itemAt(int idx) const {
|
|||
QLayoutItem *QPanelLayout::takeAt(int idx) {
|
||||
if ((idx >= 0) && (idx < m_list.size())) {
|
||||
PanelWrapper *layoutStruct = m_list.takeAt(idx);
|
||||
return layoutStruct->item;
|
||||
Q_ASSERT(layoutStruct);
|
||||
if (!layoutStruct)
|
||||
return 0;
|
||||
QLayoutItem *li = layoutStruct->item;
|
||||
delete layoutStruct;
|
||||
return li;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -243,6 +240,8 @@ QLayoutItem *QPanelLayout::takeAt(int idx) {
|
|||
\internal
|
||||
*/
|
||||
void QPanelLayout::setGeometry(const QRect &r) {
|
||||
// qDebug("laying out %i panels", count());
|
||||
|
||||
QScrollBar *vb = m_parent->verticalScrollBar(),
|
||||
*hb = m_parent->horizontalScrollBar();
|
||||
|
||||
|
@ -264,13 +263,17 @@ void QPanelLayout::setGeometry(const QRect &r) {
|
|||
continue;
|
||||
|
||||
if (position == North) {
|
||||
item->setGeometry(QRect(rect.x(), northHeight, rect.width(),
|
||||
item->sizeHint().height()));
|
||||
item->setGeometry(QRect(rect.x(), rect.y() + northHeight,
|
||||
rect.width(), item->sizeHint().height()));
|
||||
|
||||
northHeight += item->geometry().height() + spacing();
|
||||
} else if (position == South) {
|
||||
int ht = item->sizeHint().height();
|
||||
if (item->hasHeightForWidth()) {
|
||||
ht = item->heightForWidth(rect.width());
|
||||
}
|
||||
item->setGeometry(QRect(item->geometry().x(), item->geometry().y(),
|
||||
rect.width(), item->sizeHint().height()));
|
||||
rect.width(), ht));
|
||||
|
||||
southHeight += item->geometry().height() + spacing();
|
||||
|
||||
|
@ -291,7 +294,8 @@ void QPanelLayout::setGeometry(const QRect &r) {
|
|||
continue;
|
||||
|
||||
if (position == West) {
|
||||
item->setGeometry(QRect(rect.x() + westWidth, northHeight,
|
||||
item->setGeometry(QRect(rect.x() + westWidth,
|
||||
rect.y() + northHeight,
|
||||
item->sizeHint().width(), centerHeight));
|
||||
|
||||
westWidth += item->geometry().width() + spacing();
|
||||
|
@ -301,23 +305,15 @@ void QPanelLayout::setGeometry(const QRect &r) {
|
|||
|
||||
eastWidth += item->geometry().width() + spacing();
|
||||
|
||||
item->setGeometry(QRect(
|
||||
rect.x() + rect.width() - eastWidth + spacing(), northHeight,
|
||||
item->geometry().width(), item->geometry().height()));
|
||||
item->setGeometry(
|
||||
QRect(rect.x() + rect.width() - eastWidth + spacing(),
|
||||
rect.y() + northHeight, item->geometry().width(),
|
||||
item->geometry().height()));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if ( center )
|
||||
center->item->setGeometry(QRect(westWidth, northHeight,
|
||||
rect.width()
|
||||
- eastWidth - westWidth, centerHeight));
|
||||
*/
|
||||
// qDebug("{%i, %i, %i, %i}", westWidth, northHeight, eastWidth,
|
||||
// southHeight);
|
||||
|
||||
// qDebug() << westWidth;
|
||||
m_parent->setPanelMargins(westWidth, northHeight, eastWidth, southHeight);
|
||||
m_parent->setPanelMargins(westWidth, rect.y() + northHeight, eastWidth,
|
||||
southHeight);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
|
@ -157,7 +157,7 @@ QSnippetManager::patternLoader(const QString &type) const {
|
|||
return pl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void QSnippetManager::saveSnippetsToDirectory(const QString &path) {
|
||||
|
@ -179,14 +179,9 @@ void QSnippetManager::saveSnippetsToDirectory(const QString &path) {
|
|||
void QSnippetManager::loadSnippetsFromDirectory(const QString &path) {
|
||||
QDir d(path);
|
||||
|
||||
QFileInfoList l = d.entryInfoList(QDir::Files | QDir::Readable);
|
||||
|
||||
foreach (const QFileInfo &info, l) {
|
||||
if (info.suffix() != "qcs")
|
||||
continue;
|
||||
|
||||
// TODO : pattern selection?
|
||||
loadSnippetFromFile(info.absoluteFilePath(), "Simple");
|
||||
for (auto &info : d.entryInfoList({QStringLiteral("*.qcs")},
|
||||
QDir::Files | QDir::Readable)) {
|
||||
loadSnippetFromFile(info.absoluteFilePath(), QStringLiteral("Simple"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -57,7 +57,6 @@ public slots:
|
|||
|
||||
signals:
|
||||
void snippetAdded(QSnippet *s);
|
||||
|
||||
void snippetRemovedByIndex(int i);
|
||||
void snippetRemoved(QSnippet *s);
|
||||
|
||||
|
|
|
@ -63,6 +63,8 @@ QFoldPanel::~QFoldPanel() {}
|
|||
*/
|
||||
QString QFoldPanel::type() const { return "Fold indicators"; }
|
||||
|
||||
QString QFoldPanel::name() const { return tr("Fold Panel"); }
|
||||
|
||||
/*!
|
||||
|
||||
*/
|
||||
|
|
|
@ -37,6 +37,7 @@ public:
|
|||
virtual ~QFoldPanel();
|
||||
|
||||
virtual QString type() const;
|
||||
virtual QString name() const;
|
||||
|
||||
protected:
|
||||
virtual void mousePressEvent(QMouseEvent *e);
|
||||
|
|
|
@ -60,6 +60,8 @@ QLineChangePanel::~QLineChangePanel() {}
|
|||
*/
|
||||
QString QLineChangePanel::type() const { return "Line changes"; }
|
||||
|
||||
QString QLineChangePanel::name() const { return tr("Line Change Panel"); }
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
|
|
|
@ -40,6 +40,7 @@ public:
|
|||
virtual ~QLineChangePanel();
|
||||
|
||||
virtual QString type() const;
|
||||
virtual QString name() const;
|
||||
|
||||
protected:
|
||||
virtual void paint(QPainter *p, QEditor *e);
|
||||
|
|
|
@ -47,6 +47,7 @@ QCE_AUTO_REGISTER(QLineNumberPanel)
|
|||
*/
|
||||
QLineNumberPanel::QLineNumberPanel(QWidget *p) : QPanel(p), m_verbose(false) {
|
||||
setFixedWidth(20);
|
||||
setObjectName("lineNumberPanel");
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -57,7 +58,11 @@ QLineNumberPanel::~QLineNumberPanel() {}
|
|||
/*!
|
||||
|
||||
*/
|
||||
QString QLineNumberPanel::type() const { return "Line numbers"; }
|
||||
QString QLineNumberPanel::type() const {
|
||||
return QStringLiteral("Line numbers");
|
||||
}
|
||||
|
||||
QString QLineNumberPanel::name() const { return tr("Line Number Panel"); }
|
||||
|
||||
/*!
|
||||
|
||||
|
@ -72,6 +77,8 @@ void QLineNumberPanel::setVerboseMode(bool y) {
|
|||
update();
|
||||
}
|
||||
|
||||
void QLineNumberPanel::setFont_slot(const QFont &font) { setFont(font); }
|
||||
|
||||
/*!
|
||||
|
||||
*/
|
||||
|
@ -79,21 +86,20 @@ void QLineNumberPanel::editorChange(QEditor *e) {
|
|||
if (editor()) {
|
||||
disconnect(editor(), SIGNAL(cursorPositionChanged()), this,
|
||||
SLOT(update()));
|
||||
disconnect(editor()->document(), SIGNAL(fontChanged(QFont)), this,
|
||||
SLOT(setFont_slot(QFont)));
|
||||
}
|
||||
|
||||
if (e) {
|
||||
_fixWidth =
|
||||
QFontMetrics(e->document()->font())
|
||||
.horizontalAdvance(QString::number(e->document()->lines())) +
|
||||
5;
|
||||
setFixedWidth(fontMetrics().horizontalAdvance(
|
||||
QString::number(e->document()->lines())) +
|
||||
5);
|
||||
|
||||
connect(e, SIGNAL(cursorPositionChanged()), this, SLOT(update()));
|
||||
connect(e, &QEditor::zoomed, this, [=] {
|
||||
_fixWidth = QFontMetrics(e->document()->font())
|
||||
.horizontalAdvance(
|
||||
QString::number(e->document()->lines())) +
|
||||
5;
|
||||
});
|
||||
connect(e, &QEditor::cursorPositionChanged, this,
|
||||
QOverload<>::of(&QLineNumberPanel::update));
|
||||
|
||||
connect(e->document(), &QDocument::fontChanged, this,
|
||||
&QLineNumberPanel::setFont_slot);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,35 +108,48 @@ void QLineNumberPanel::editorChange(QEditor *e) {
|
|||
*/
|
||||
void QLineNumberPanel::paint(QPainter *p, QEditor *e) {
|
||||
/*
|
||||
possible Unicode caracter for wrapping arrow :
|
||||
0x21B3
|
||||
0x2937
|
||||
*/
|
||||
possible Unicode caracter for wrapping arrow :
|
||||
0x21B3
|
||||
0x2937
|
||||
*/
|
||||
|
||||
QFont f(font());
|
||||
f.setWeight(QFont::Bold);
|
||||
// f.setWeight(QFont::Bold);
|
||||
const QFontMetrics sfm(f);
|
||||
bool specialFontUsage = false;
|
||||
QFont specialFont(font());
|
||||
|
||||
#ifndef WIN32
|
||||
static const QChar wrappingArrow(0x2937);
|
||||
const QFontMetrics specialSfm(sfm);
|
||||
#if QT_VERSION >= 0x050000 && defined Q_OS_MAC && (QT_VERSION < 0x050200)
|
||||
if (!specialSfm.inFont(wrappingArrow)) {
|
||||
specialFontUsage = true;
|
||||
specialFont.setFamily("Gothic Regular");
|
||||
// specialSfm(specialFont);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
// 0xC4 gives a decent wrapping arrow in Wingdings fonts, availables on all
|
||||
// windows systems this is a hackish fallback to workaround Windows issues
|
||||
// with Unicode...
|
||||
// windows systems
|
||||
// this is a hackish fallback to workaround Windows issues with Unicode...
|
||||
static const QChar wrappingArrow(0xC4);
|
||||
QFont specialFont(font());
|
||||
specialFont.setFamily("Wingdings");
|
||||
const QFontMetrics specialSfm(specialFont);
|
||||
specialFontUsage = true;
|
||||
#endif
|
||||
|
||||
const int max = e->document()->lines();
|
||||
const int panelWidth = sfm.horizontalAdvance(QString::number(max)) + 5;
|
||||
int max = e->document()->lines();
|
||||
if (max < 100)
|
||||
max = 100; // always reserve 3 line number columns to avoid ugly jumping
|
||||
// of width
|
||||
QString s_width = QString::number(max);
|
||||
s_width.fill('6');
|
||||
const int panelWidth = sfm.horizontalAdvance(s_width) + 5;
|
||||
setFixedWidth(panelWidth);
|
||||
|
||||
const QFontMetrics fm(e->document()->font());
|
||||
|
||||
int n, posY, as = fm.ascent(), ls = fm.lineSpacing(),
|
||||
int n, posY, as = QFontMetrics(e->document()->font()).ascent(),
|
||||
ls = e->document()->lineSpacing(),
|
||||
pageBottom = e->viewport()->height(),
|
||||
contentsY = e->verticalOffset();
|
||||
|
||||
|
@ -144,12 +163,6 @@ void QLineNumberPanel::paint(QPainter *p, QEditor *e) {
|
|||
// qDebug("first = %i; last = %i", first, last);
|
||||
// qDebug("beg pos : %i", posY);
|
||||
|
||||
p->save();
|
||||
f = p->font();
|
||||
f.setPointSize(d->font().pointSize());
|
||||
|
||||
p->setFont(f);
|
||||
|
||||
for (;; ++n) {
|
||||
// qDebug("n = %i; pos = %i", n, posY);
|
||||
QDocumentLine line = d->line(n);
|
||||
|
@ -163,22 +176,42 @@ void QLineNumberPanel::paint(QPainter *p, QEditor *e) {
|
|||
bool draw = true;
|
||||
|
||||
if (!m_verbose) {
|
||||
draw = !((n + 1) % 10) || !n || line.marks().count();
|
||||
draw = !((n + 1) % 10) || !n || !line.marks().empty();
|
||||
}
|
||||
|
||||
txt = QString::number(n + 1);
|
||||
|
||||
if (n == cursorLine) {
|
||||
draw = true;
|
||||
|
||||
p->save();
|
||||
auto f = p->font();
|
||||
QFont f = p->font();
|
||||
f.setBold(true);
|
||||
f.setUnderline(true);
|
||||
p->setFont(f);
|
||||
}
|
||||
|
||||
if (draw) {
|
||||
p->drawText(width() - 2 - sfm.horizontalAdvance(txt), posY, txt);
|
||||
if (specialFontUsage) {
|
||||
if (line.lineSpan() > 1) {
|
||||
p->save();
|
||||
specialFont.setBold(n ==
|
||||
cursorLine); // todo: only get bold on
|
||||
// the current wrapped line
|
||||
p->setFont(specialFont);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 1; i < line.lineSpan(); ++i)
|
||||
p->drawText(width() - 2 -
|
||||
specialSfm.horizontalAdvance(wrappingArrow),
|
||||
posY + i * ls, wrappingArrow);
|
||||
|
||||
if (specialFontUsage) {
|
||||
if (line.lineSpan() > 1)
|
||||
p->restore();
|
||||
}
|
||||
} else {
|
||||
int yOff = posY - (as + 1) + ls / 2;
|
||||
|
||||
|
@ -188,30 +221,6 @@ void QLineNumberPanel::paint(QPainter *p, QEditor *e) {
|
|||
p->drawLine(width() - 7, yOff, width() - 2, yOff);
|
||||
}
|
||||
|
||||
if (line.lineSpan() > 1) {
|
||||
#ifdef Q_OS_WIN32
|
||||
p->save();
|
||||
specialFont.setBold(
|
||||
n ==
|
||||
cursorLine); // todo: only get bold on the current wrapped line
|
||||
specialFont.setPointSize(d->font().pointSize());
|
||||
p->setFont(specialFont);
|
||||
#endif
|
||||
|
||||
for (int i = 1; i < line.lineSpan(); ++i) {
|
||||
// draw line wrapping indicators
|
||||
// p->drawText(width() - 2 - sfm.width(wrappingArrow), posY + i
|
||||
// * ls, wrappingArrow);
|
||||
p->drawText(width() - 1 -
|
||||
specialSfm.horizontalAdvance(wrappingArrow),
|
||||
posY + i * ls, wrappingArrow);
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
p->restore();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (n == cursorLine) {
|
||||
p->restore();
|
||||
}
|
||||
|
@ -219,8 +228,6 @@ void QLineNumberPanel::paint(QPainter *p, QEditor *e) {
|
|||
posY += ls * line.lineSpan();
|
||||
}
|
||||
|
||||
p->restore();
|
||||
|
||||
// p->setPen(Qt::DotLine);
|
||||
// p->drawLine(width()-1, 0, width()-1, pageBottom);
|
||||
|
||||
|
|
|
@ -37,12 +37,15 @@ public:
|
|||
bool isVerboseMode() const;
|
||||
|
||||
virtual QString type() const;
|
||||
virtual QString name() const;
|
||||
|
||||
virtual QSize sizeHint() const;
|
||||
|
||||
public slots:
|
||||
void setVerboseMode(bool y);
|
||||
|
||||
void setFont_slot(const QFont &font);
|
||||
|
||||
protected:
|
||||
virtual void editorChange(QEditor *e);
|
||||
virtual void paint(QPainter *p, QEditor *e);
|
||||
|
|
|
@ -88,6 +88,8 @@ QPanel::~QPanel() {
|
|||
// qDebug("Panels cleared.");
|
||||
}
|
||||
|
||||
QString QPanel::name() const { return type(); }
|
||||
|
||||
/*!
|
||||
*/
|
||||
QEditor *QPanel::editor() { return m_editor; }
|
||||
|
@ -107,7 +109,7 @@ void QPanel::attach(QEditor *e) {
|
|||
this, SLOT(update()));
|
||||
}
|
||||
|
||||
editorChange(e);
|
||||
QPanel::editorChange(e);
|
||||
|
||||
m_editor = e;
|
||||
setParent(e);
|
||||
|
|
|
@ -46,6 +46,7 @@ public:
|
|||
|
||||
virtual QString id() const = 0;
|
||||
virtual QString type() const = 0;
|
||||
virtual QString name() const;
|
||||
|
||||
QEditor *editor();
|
||||
void attach(QEditor *e);
|
||||
|
|
|
@ -1,83 +0,0 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
|
||||
**
|
||||
** This file is part of the Edyuk project <http://edyuk.org>
|
||||
**
|
||||
** This file may be used under the terms of the GNU General Public License
|
||||
** version 3 as published by the Free Software Foundation and appearing in the
|
||||
** file GPL.txt included in the packaging of this file.
|
||||
**
|
||||
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qsimplecolorpicker.h"
|
||||
|
||||
/*!
|
||||
\file qsimplecolorpicker.cpp
|
||||
\brief Implementation of the QSimpleColorPicker class
|
||||
*/
|
||||
|
||||
#include <QColorDialog>
|
||||
#include <QIcon>
|
||||
#include <QPainter>
|
||||
#include <QPixmap>
|
||||
#include <QResizeEvent>
|
||||
|
||||
QSimpleColorPicker::QSimpleColorPicker(QWidget *w) : QToolButton(w) {
|
||||
setColor(QColor());
|
||||
|
||||
connect(this, SIGNAL(clicked()), this, SLOT(clicked()));
|
||||
}
|
||||
|
||||
QSimpleColorPicker::QSimpleColorPicker(const QColor &c, QWidget *w)
|
||||
: QToolButton(w) {
|
||||
setColor(c);
|
||||
|
||||
connect(this, SIGNAL(clicked()), this, SLOT(clicked()));
|
||||
}
|
||||
|
||||
const QColor &QSimpleColorPicker::color() const { return m_color; }
|
||||
|
||||
void QSimpleColorPicker::setColor(const QColor &c) {
|
||||
m_color = c;
|
||||
|
||||
updateIcon(size());
|
||||
}
|
||||
|
||||
void QSimpleColorPicker::resizeEvent(QResizeEvent *e) {
|
||||
updateIcon(e->size());
|
||||
|
||||
QToolButton::resizeEvent(e);
|
||||
}
|
||||
|
||||
void QSimpleColorPicker::contextMenuEvent(QContextMenuEvent *e) {
|
||||
setColor(QColor());
|
||||
|
||||
e->accept();
|
||||
|
||||
QToolButton::contextMenuEvent(e);
|
||||
}
|
||||
|
||||
void QSimpleColorPicker::updateIcon(const QSize &sz) {
|
||||
QPixmap px(sz.width() - 3, sz.height() - 3);
|
||||
QPainter p(&px);
|
||||
|
||||
if (m_color.isValid()) {
|
||||
p.fillRect(0, 0, px.width(), px.height(), m_color);
|
||||
setIcon(QIcon(px));
|
||||
} else {
|
||||
// p.fillRect(0, 0, px.width(), px.height(), palette().window());
|
||||
setIcon(QIcon());
|
||||
}
|
||||
}
|
||||
|
||||
void QSimpleColorPicker::clicked() {
|
||||
QColor c = QColorDialog::getColor(m_color);
|
||||
|
||||
if (c.isValid()) {
|
||||
setColor(c);
|
||||
}
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
|
||||
**
|
||||
** This file is part of the Edyuk project <http://edyuk.org>
|
||||
**
|
||||
** This file may be used under the terms of the GNU General Public License
|
||||
** version 3 as published by the Free Software Foundation and appearing in the
|
||||
** file GPL.txt included in the packaging of this file.
|
||||
**
|
||||
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _QSIMPLE_COLOR_PICKER_H_
|
||||
#define _QSIMPLE_COLOR_PICKER_H_
|
||||
|
||||
#include "qce-config.h"
|
||||
|
||||
/*!
|
||||
\file qsimplecolorpicker.h
|
||||
\brief Definition of the QSimpleColorPicker class
|
||||
*/
|
||||
|
||||
#include <QToolButton>
|
||||
|
||||
class QCE_EXPORT QSimpleColorPicker : public QToolButton {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QColor color READ color WRITE setColor)
|
||||
|
||||
public:
|
||||
QSimpleColorPicker(QWidget *w = 0);
|
||||
QSimpleColorPicker(const QColor &c, QWidget *w = 0);
|
||||
|
||||
const QColor &color() const;
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
void contextMenuEvent(QContextMenuEvent *e);
|
||||
|
||||
public slots:
|
||||
void setColor(const QColor &c);
|
||||
|
||||
void updateIcon(const QSize &sz);
|
||||
|
||||
private slots:
|
||||
void clicked();
|
||||
|
||||
private:
|
||||
QColor m_color;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -70,16 +70,12 @@ set(ANGEL_SCRIPT_ADDON
|
|||
${ANGEL_SCRIPT_ADDON_ROOT}/autowrapper/aswrappedcall.h
|
||||
${ANGEL_SCRIPT_ADDON_ROOT}/contextmgr/contextmgr.cpp
|
||||
${ANGEL_SCRIPT_ADDON_ROOT}/contextmgr/contextmgr.h
|
||||
${ANGEL_SCRIPT_ADDON_ROOT}/datetime/datetime.cpp
|
||||
${ANGEL_SCRIPT_ADDON_ROOT}/datetime/datetime.h
|
||||
${ANGEL_SCRIPT_ADDON_ROOT}/scriptany/scriptany.cpp
|
||||
${ANGEL_SCRIPT_ADDON_ROOT}/scriptany/scriptany.h
|
||||
${ANGEL_SCRIPT_ADDON_ROOT}/scriptarray/scriptarray.cpp
|
||||
${ANGEL_SCRIPT_ADDON_ROOT}/scriptarray/scriptarray.h
|
||||
${ANGEL_SCRIPT_ADDON_ROOT}/scriptfile/scriptfile.cpp
|
||||
${ANGEL_SCRIPT_ADDON_ROOT}/scriptfile/scriptfile.h
|
||||
${ANGEL_SCRIPT_ADDON_ROOT}/scriptfile/scriptfilesystem.cpp
|
||||
${ANGEL_SCRIPT_ADDON_ROOT}/scriptfile/scriptfilesystem.h
|
||||
${ANGEL_SCRIPT_ADDON_ROOT}/scriptgrid/scriptgrid.cpp
|
||||
${ANGEL_SCRIPT_ADDON_ROOT}/scriptgrid/scriptgrid.h
|
||||
${ANGEL_SCRIPT_ADDON_ROOT}/scripthandle/scripthandle.cpp
|
||||
|
@ -152,7 +148,12 @@ set(DIALOG_SRC
|
|||
src/dialog/checksumdialog.cpp
|
||||
src/dialog/colorpickerdialog.h
|
||||
src/dialog/colorpickerdialog.cpp
|
||||
src/dialog/colorpickerdialog.ui)
|
||||
src/dialog/colorpickerdialog.ui
|
||||
src/dialog/showtextdialog.h
|
||||
src/dialog/showtextdialog.cpp
|
||||
src/dialog/splashdialog.ui
|
||||
src/dialog/splashdialog.cpp
|
||||
src/dialog/splashdialog.h)
|
||||
|
||||
set(CONTROL_SRC
|
||||
src/control/editorview.h
|
||||
|
@ -176,7 +177,11 @@ set(CONTROL_SRC
|
|||
src/control/qlistviewext.cpp
|
||||
src/control/qcodecompletionwidget.h
|
||||
src/control/qcodecompletionwidget_p.h
|
||||
src/control/qcodecompletionwidget.cpp)
|
||||
src/control/qcodecompletionwidget.cpp
|
||||
src/control/codeedit.h
|
||||
src/control/codeedit.cpp
|
||||
src/control/asobjtreewidget.h
|
||||
src/control/asobjtreewidget.cpp)
|
||||
|
||||
set(CLASS_SRC
|
||||
src/class/logger.cpp
|
||||
|
@ -234,7 +239,9 @@ set(CLASS_SRC
|
|||
src/class/langservice.h
|
||||
src/class/langservice.cpp
|
||||
src/class/clangformatmanager.h
|
||||
src/class/clangformatmanager.cpp)
|
||||
src/class/clangformatmanager.cpp
|
||||
src/class/aspreprocesser.h
|
||||
src/class/aspreprocesser.cpp)
|
||||
|
||||
if(WINGHEX_USE_FRAMELESS)
|
||||
set(WIDGET_FRAME_SRC
|
||||
|
@ -283,9 +290,6 @@ set(SETTING_SRC
|
|||
src/settings/scriptsettingdialog.h
|
||||
src/settings/scriptsettingdialog.cpp
|
||||
src/settings/scriptsettingdialog.ui
|
||||
src/settings/scriptbehaviorsettingdialog.h
|
||||
src/settings/scriptbehaviorsettingdialog.cpp
|
||||
src/settings/scriptbehaviorsettingdialog.ui
|
||||
src/settings/othersettingsdialog.h
|
||||
src/settings/othersettingsdialog.cpp
|
||||
src/settings/othersettingsdialog.ui
|
||||
|
@ -320,7 +324,9 @@ set(CODEEDIT_WIDGET
|
|||
src/qcodeeditwidget/qsnippetedit.h
|
||||
src/qcodeeditwidget/qsnippetedit.ui
|
||||
src/qcodeeditwidget/qdocumentswaptextcommand.h
|
||||
src/qcodeeditwidget/qdocumentswaptextcommand.cpp)
|
||||
src/qcodeeditwidget/qdocumentswaptextcommand.cpp
|
||||
src/qcodeeditwidget/formatconfigmodel.h
|
||||
src/qcodeeditwidget/formatconfigmodel.cpp)
|
||||
|
||||
set(PLUGIN_SRC src/plugin/iwingplugin.h src/plugin/pluginsystem.cpp
|
||||
src/plugin/pluginsystem.h src/plugin/settingpage.h)
|
||||
|
@ -377,8 +383,7 @@ foreach(TS_FILE IN LISTS TS_FILES)
|
|||
"${LANG_NEED_COPY_PREFIX}/about.md"
|
||||
"${LANG_NEED_COPY_PREFIX}/components.md"
|
||||
"${LANG_NEED_COPY_PREFIX}/credits.md"
|
||||
"${LANG_NEED_COPY_PREFIX}/devs.md"
|
||||
"${LANG_NEED_COPY_PREFIX}/trans.md")
|
||||
"${LANG_NEED_COPY_PREFIX}/devs.md")
|
||||
add_custom_target(
|
||||
copy_lang_files
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${LANG_NEED_COPY} ${QM_DIR}
|
||||
|
@ -387,7 +392,7 @@ foreach(TS_FILE IN LISTS TS_FILES)
|
|||
set(LANG_PAK "${QM_DIR}/${LANG_PAK_NAME}")
|
||||
|
||||
set(LANG_COMPRESS_CONTENT "winghex.qm" "about.md" "components.md"
|
||||
"credits.md" "devs.md" "trans.md")
|
||||
"credits.md" "devs.md")
|
||||
|
||||
add_custom_target(
|
||||
pak_lang_files
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 310 B After Width: | Height: | Size: 4.5 KiB |
Binary file not shown.
After Width: | Height: | Size: 6.7 KiB |
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
Binary file not shown.
After Width: | Height: | Size: 6.7 KiB |
|
@ -1,2 +0,0 @@
|
|||
|
||||
* 简体中文:寂静的羽夏(wingsummer)【原生支持】
|
File diff suppressed because it is too large
Load Diff
21
main.cpp
21
main.cpp
|
@ -1,4 +1,5 @@
|
|||
#include "class/appmanager.h"
|
||||
#include "class/settingmanager.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
/* 有关对在 QT5 的 Win 平台禁用高 dpi 支持
|
||||
|
@ -19,8 +20,24 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
AppManager a(argc, argv);
|
||||
auto w = a.mainWindow();
|
||||
w->show();
|
||||
Utilities::moveToCenter(w);
|
||||
|
||||
auto &set = SettingManager::instance();
|
||||
switch (set.defaultWinState()) {
|
||||
case Qt::WindowNoState:
|
||||
w->show();
|
||||
Utilities::moveToCenter(w);
|
||||
break;
|
||||
case Qt::WindowMinimized:
|
||||
w->showMinimized();
|
||||
break;
|
||||
case Qt::WindowActive:
|
||||
case Qt::WindowMaximized:
|
||||
w->showMaximized();
|
||||
break;
|
||||
case Qt::WindowFullScreen:
|
||||
w->showFullScreen();
|
||||
break;
|
||||
}
|
||||
|
||||
return a.exec();
|
||||
}
|
||||
|
|
|
@ -77,6 +77,7 @@
|
|||
<file>images/savesel.png</file>
|
||||
<file>images/scale.png</file>
|
||||
<file>images/scalereset.png</file>
|
||||
<file>images/scheme.png</file>
|
||||
<file>images/script.png</file>
|
||||
<file>images/scriptdbg/bp.png</file>
|
||||
<file>images/scriptdbg/bpdis.png</file>
|
||||
|
@ -89,6 +90,7 @@
|
|||
<file>images/scriptdbg/warn.png</file>
|
||||
<file>images/scriptfolder.png</file>
|
||||
<file>images/scriptfolderusr.png</file>
|
||||
<file>images/scriptset.png</file>
|
||||
<file>images/setting.png</file>
|
||||
<file>images/settingplugin.png</file>
|
||||
<file>images/snippt.png</file>
|
||||
|
@ -99,11 +101,13 @@
|
|||
<file>images/unlock.png</file>
|
||||
<file>images/unover.png</file>
|
||||
<file>images/unsaved.png</file>
|
||||
<file>images/viewtxt.png</file>
|
||||
<file>images/wiki.png</file>
|
||||
<file>images/win.png</file>
|
||||
<file>images/workspace.png</file>
|
||||
<file>images/writable.png</file>
|
||||
<file>src/TESTCODE.as</file>
|
||||
<file>src/translist.md</file>
|
||||
</qresource>
|
||||
<qresource prefix="/qpathedit/icons">
|
||||
<file alias="dialog.ico">3rdparty/QPathEdit/Fatcow-Farm-Fresh-Dialog.ico</file>
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
*/
|
||||
|
||||
#include "angelobjstring.h"
|
||||
#include "AngelScript/sdk/add_on/datetime/datetime.h"
|
||||
#include "AngelScript/sdk/add_on/scriptarray/scriptarray.h"
|
||||
#include "scriptaddon/scriptqdictionary.h"
|
||||
|
||||
|
@ -71,6 +70,16 @@ QString AngelObjString::arrayToString(void *obj, int expandMembers,
|
|||
return str;
|
||||
}
|
||||
|
||||
QString AngelObjString::charToString(void *obj, int expandMembers,
|
||||
asDebugger *dbg) {
|
||||
Q_UNUSED(expandMembers);
|
||||
Q_UNUSED(dbg);
|
||||
|
||||
// We know the received object is a char
|
||||
QChar *val = reinterpret_cast<QChar *>(obj);
|
||||
return QString(*val);
|
||||
}
|
||||
|
||||
QString AngelObjString::dictionaryToString(void *obj, int expandMembers,
|
||||
asDebugger *dbg) {
|
||||
CScriptDictionary *dic = reinterpret_cast<CScriptDictionary *>(obj);
|
||||
|
@ -108,23 +117,6 @@ QString AngelObjString::dictionaryToString(void *obj, int expandMembers,
|
|||
return str;
|
||||
}
|
||||
|
||||
QString AngelObjString::dateTimeToString(void *obj, int expandMembers,
|
||||
asDebugger *dbg) {
|
||||
Q_UNUSED(expandMembers);
|
||||
Q_UNUSED(dbg);
|
||||
|
||||
CDateTime *dt = reinterpret_cast<CDateTime *>(obj);
|
||||
|
||||
QString str;
|
||||
QTextStream s(&str);
|
||||
s << "{" << dt->getYear() << "-" << dt->getMonth() << "-" << dt->getDay()
|
||||
<< " ";
|
||||
s << dt->getHour() << ":" << dt->getMinute() << ":" << dt->getSecond()
|
||||
<< "}";
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
QString AngelObjString::getEscapedString(const ushort *begin, int length,
|
||||
bool isUnicode) {
|
||||
Q_STATIC_ASSERT(sizeof(ushort) == sizeof(QChar));
|
||||
|
|
|
@ -34,12 +34,11 @@ public:
|
|||
|
||||
static QString arrayToString(void *obj, int expandMembers, asDebugger *dbg);
|
||||
|
||||
static QString charToString(void *obj, int expandMembers, asDebugger *dbg);
|
||||
|
||||
static QString dictionaryToString(void *obj, int expandMembers,
|
||||
asDebugger *dbg);
|
||||
|
||||
static QString dateTimeToString(void *obj, int expandMembers,
|
||||
asDebugger *dbg);
|
||||
|
||||
public:
|
||||
// ==================================================
|
||||
// the following codes are from QT offical code (LGPL)
|
||||
|
|
|
@ -19,16 +19,17 @@
|
|||
|
||||
#include <QFont>
|
||||
|
||||
#include "class/clangformatmanager.h"
|
||||
#include "class/langservice.h"
|
||||
#include "class/logger.h"
|
||||
#include "languagemanager.h"
|
||||
#include "settingmanager.h"
|
||||
#include "skinmanager.h"
|
||||
|
||||
#include "angelscript.h"
|
||||
#include "clangformatmanager.h"
|
||||
#include "dbghelper.h"
|
||||
#include "dialog/mainwindow.h"
|
||||
#include "dialog/splashdialog.h"
|
||||
#include "languagemanager.h"
|
||||
#include "logger.h"
|
||||
#include "settingmanager.h"
|
||||
#include "skinmanager.h"
|
||||
#include "utilities.h"
|
||||
#include "wingmessagebox.h"
|
||||
|
||||
AppManager *AppManager::_instance = nullptr;
|
||||
|
||||
|
@ -52,6 +53,20 @@ AppManager::AppManager(int &argc, char *argv[])
|
|||
sendMessage(buffer);
|
||||
}
|
||||
|
||||
#ifndef ANGELSCRIPT_H
|
||||
#error "You should include angelscript.h header to check the PORTABILITY"
|
||||
#else
|
||||
#ifdef AS_MAX_PORTABILITY
|
||||
#error "Generic call is NOT FULLY SUPPORTED in WingHexExplorer2 library!"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY")) {
|
||||
WingMessageBox::critical(nullptr, qAppName(),
|
||||
tr("GenericCallNotFullySupported"));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
Logger::instance();
|
||||
|
||||
auto &set = SettingManager::instance();
|
||||
|
@ -60,9 +75,17 @@ AppManager::AppManager(int &argc, char *argv[])
|
|||
|
||||
SkinManager::instance();
|
||||
LanguageManager::instance();
|
||||
ClangFormatManager::instance();
|
||||
|
||||
_w = new MainWindow;
|
||||
auto dontSplash = set.dontUseSplash();
|
||||
|
||||
SplashDialog *splash = nullptr;
|
||||
if (!dontSplash) {
|
||||
splash = new SplashDialog;
|
||||
splash->setInfoText(tr("SetupClang"));
|
||||
ClangFormatManager::instance();
|
||||
}
|
||||
|
||||
_w = new MainWindow(splash);
|
||||
|
||||
connect(this, &SingleApplication::instanceStarted, this, [this] {
|
||||
Q_ASSERT(_w);
|
||||
|
@ -85,6 +108,9 @@ AppManager::AppManager(int &argc, char *argv[])
|
|||
}
|
||||
});
|
||||
|
||||
if (splash)
|
||||
splash->setInfoText(tr("OpeningFiles"));
|
||||
|
||||
if (args.size() > 1) {
|
||||
for (auto var = args.begin() + 1; var != args.end(); ++var) {
|
||||
openFile(*var);
|
||||
|
@ -92,9 +118,14 @@ AppManager::AppManager(int &argc, char *argv[])
|
|||
}
|
||||
|
||||
_instance = this;
|
||||
|
||||
if (splash)
|
||||
splash->close();
|
||||
}
|
||||
|
||||
AppManager::~AppManager() {
|
||||
ClangFormatManager::instance().save();
|
||||
|
||||
_w->deleteLater();
|
||||
_w = nullptr;
|
||||
}
|
||||
|
|
|
@ -22,578 +22,36 @@
|
|||
#include <QFileInfo>
|
||||
#include <QObject>
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
asBuilder::asBuilder() {
|
||||
engine = nullptr;
|
||||
asBuilder::asBuilder(asIScriptEngine *engine) : AsPreprocesser(engine) {
|
||||
module = nullptr;
|
||||
|
||||
includeCallback = nullptr;
|
||||
includeParam = nullptr;
|
||||
|
||||
pragmaCallback = nullptr;
|
||||
pragmaParam = nullptr;
|
||||
}
|
||||
|
||||
void asBuilder::SetIncludeCallback(INCLUDECALLBACK_t callback,
|
||||
void *userParam) {
|
||||
includeCallback = callback;
|
||||
includeParam = userParam;
|
||||
}
|
||||
|
||||
void asBuilder::SetPragmaCallback(PRAGMACALLBACK_t callback, void *userParam) {
|
||||
pragmaCallback = callback;
|
||||
pragmaParam = userParam;
|
||||
}
|
||||
|
||||
int asBuilder::StartNewModule(asIScriptEngine *inEngine,
|
||||
const char *moduleName) {
|
||||
if (inEngine == nullptr)
|
||||
return -1;
|
||||
|
||||
engine = inEngine;
|
||||
module = inEngine->GetModule(moduleName, asGM_ALWAYS_CREATE);
|
||||
int asBuilder::StartNewModule(const char *moduleName) {
|
||||
module = engine->GetModule(moduleName, asGM_ALWAYS_CREATE);
|
||||
if (module == nullptr)
|
||||
return -1;
|
||||
|
||||
ClearAll();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
asIScriptEngine *asBuilder::GetEngine() { return engine; }
|
||||
|
||||
asIScriptModule *asBuilder::GetModule() { return module; }
|
||||
|
||||
unsigned int asBuilder::GetSectionCount() const {
|
||||
return (unsigned int)(includedScripts.size());
|
||||
}
|
||||
|
||||
QString asBuilder::GetSectionName(unsigned int idx) const {
|
||||
if (qsizetype(idx) >= qsizetype(includedScripts.size()))
|
||||
return {};
|
||||
|
||||
return includedScripts.at(idx);
|
||||
}
|
||||
|
||||
// Returns 1 if the section was included
|
||||
// Returns 0 if the section was not included because it had already been
|
||||
// included before Returns <0 if there was an error
|
||||
int asBuilder::AddSectionFromFile(const QString &filename) {
|
||||
// The file name stored in the set should be the fully resolved name because
|
||||
// it is possible to name the same file in multiple ways using relative
|
||||
// paths.
|
||||
auto fullpath = QFileInfo(filename).absoluteFilePath();
|
||||
|
||||
if (IncludeIfNotAlreadyIncluded(fullpath)) {
|
||||
int r = LoadScriptSection(fullpath);
|
||||
if (r < 0)
|
||||
return r;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Returns 1 if the section was included
|
||||
// Returns 0 if the section was not included because it had already been
|
||||
// included before Returns <0 if there was an error
|
||||
int asBuilder::AddSectionFromMemory(const char *sectionName,
|
||||
const char *scriptCode,
|
||||
unsigned int scriptLength, int lineOffset) {
|
||||
if (IncludeIfNotAlreadyIncluded(sectionName)) {
|
||||
int r = ProcessScriptSection(scriptCode, scriptLength, sectionName,
|
||||
lineOffset);
|
||||
if (r < 0)
|
||||
return r;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int asBuilder::BuildModule() { return Build(); }
|
||||
|
||||
void asBuilder::DefineWord(const QString &word) {
|
||||
if (!definedWords.contains(word)) {
|
||||
definedWords.append(word);
|
||||
}
|
||||
}
|
||||
|
||||
void asBuilder::ClearAll() {
|
||||
includedScripts.clear();
|
||||
|
||||
#if AS_PROCESS_METADATA == 1
|
||||
currentClass.clear();
|
||||
currentNamespace.clear();
|
||||
|
||||
foundDeclarations.clear();
|
||||
typeMetadataMap.clear();
|
||||
funcMetadataMap.clear();
|
||||
varMetadataMap.clear();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool asBuilder::IncludeIfNotAlreadyIncluded(const QString &filename) {
|
||||
if (includedScripts.contains(filename)) {
|
||||
// Already included
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add the file to the set of included sections
|
||||
includedScripts.append(filename);
|
||||
return true;
|
||||
}
|
||||
|
||||
int asBuilder::LoadScriptSection(const QString &filename) {
|
||||
// Open the script file
|
||||
|
||||
QFile f(filename);
|
||||
|
||||
if (!f.open(QFile::ReadOnly)) {
|
||||
// Write a message to the engine's message callback
|
||||
auto msg = QObject::tr("Failed to open script file ") +
|
||||
QStringLiteral("'") +
|
||||
QFileInfo(filename).absoluteFilePath() + QStringLiteral("'");
|
||||
engine->WriteMessage(filename.toUtf8(), 0, 0, asMSGTYPE_ERROR,
|
||||
msg.toUtf8());
|
||||
|
||||
// TODO: Write the file where this one was included from
|
||||
|
||||
int asBuilder::Build() {
|
||||
Q_ASSERT(module);
|
||||
if (module == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Read the entire file
|
||||
auto code = f.readAll();
|
||||
f.close();
|
||||
|
||||
// Process the script section even if it is zero length so that the name is
|
||||
// registered
|
||||
return ProcessScriptSection(code, code.length(), filename, 0);
|
||||
}
|
||||
|
||||
int asBuilder::ProcessScriptSection(const QByteArray &script, int length,
|
||||
const QString §ionname,
|
||||
int lineOffset) {
|
||||
QVector<QPair<QString, bool>> includes;
|
||||
|
||||
// Perform a superficial parsing of the script first to store the metadata
|
||||
if (length)
|
||||
modifiedScript = script.left(length);
|
||||
else
|
||||
modifiedScript = script;
|
||||
|
||||
// First perform the checks for #if directives to exclude code that
|
||||
// shouldn't be compiled
|
||||
unsigned int pos = 0;
|
||||
int nested = 0;
|
||||
while (qsizetype(pos) < modifiedScript.size()) {
|
||||
asUINT len = 0;
|
||||
asETokenClass t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
if (t == asTC_UNKNOWN && modifiedScript[pos] == '#' &&
|
||||
(qsizetype(pos) + 1 < modifiedScript.size())) {
|
||||
int start = pos++;
|
||||
|
||||
// Is this an #if directive?
|
||||
t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
Q_UNUSED(t);
|
||||
|
||||
QByteArray token = modifiedScript.mid(pos, len);
|
||||
pos += len;
|
||||
|
||||
if (token == "if") {
|
||||
t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
if (t == asTC_WHITESPACE) {
|
||||
pos += len;
|
||||
t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
}
|
||||
|
||||
if (t == asTC_IDENTIFIER) {
|
||||
QByteArray word = modifiedScript.mid(pos, len);
|
||||
|
||||
// Overwrite the #if directive with space characters to
|
||||
// avoid compiler error
|
||||
pos += len;
|
||||
OverwriteCode(start, pos - start);
|
||||
|
||||
// Has this identifier been defined by the application or
|
||||
// not?
|
||||
if (!definedWords.contains(word)) {
|
||||
// Exclude all the code until and including the #endif
|
||||
pos = ExcludeCode(pos);
|
||||
} else {
|
||||
nested++;
|
||||
}
|
||||
}
|
||||
} else if (token == "endif") {
|
||||
// Only remove the #endif if there was a matching #if
|
||||
if (nested > 0) {
|
||||
OverwriteCode(start, pos - start);
|
||||
nested--;
|
||||
}
|
||||
}
|
||||
} else
|
||||
pos += len;
|
||||
for (auto &mod : modifiedScripts) {
|
||||
module->AddScriptSection(mod.section.toUtf8(), mod.script.data(),
|
||||
mod.script.size(), mod.lineOffset);
|
||||
}
|
||||
|
||||
#if AS_PROCESS_METADATA == 1
|
||||
// Preallocate memory
|
||||
QString name, declaration;
|
||||
QVector<QString> metadata;
|
||||
declaration.reserve(100);
|
||||
#endif
|
||||
|
||||
// Then check for meta data and pre-processor directives
|
||||
pos = 0;
|
||||
while (qsizetype(pos) < modifiedScript.size()) {
|
||||
asUINT len = 0;
|
||||
asETokenClass t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
if (t == asTC_COMMENT || t == asTC_WHITESPACE) {
|
||||
pos += len;
|
||||
continue;
|
||||
}
|
||||
QString token = modifiedScript.mid(pos, len);
|
||||
|
||||
#if AS_PROCESS_METADATA == 1
|
||||
// Skip possible decorators before class and interface declarations
|
||||
if (token == "shared" || token == "abstract" || token == "mixin" ||
|
||||
token == "external") {
|
||||
pos += len;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if class or interface so the metadata for members can be
|
||||
// gathered
|
||||
if (currentClass.isEmpty() &&
|
||||
(token == "class" || token == "interface")) {
|
||||
// Get the identifier after "class"
|
||||
do {
|
||||
pos += len;
|
||||
if (qsizetype(pos) >= modifiedScript.size()) {
|
||||
t = asTC_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
} while (t == asTC_COMMENT || t == asTC_WHITESPACE);
|
||||
|
||||
if (t == asTC_IDENTIFIER) {
|
||||
currentClass = modifiedScript.mid(pos, len);
|
||||
|
||||
// Search until first { or ; is encountered
|
||||
while (qsizetype(pos) < modifiedScript.length()) {
|
||||
engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
|
||||
// If start of class section encountered stop
|
||||
if (modifiedScript[pos] == '{') {
|
||||
pos += len;
|
||||
break;
|
||||
} else if (modifiedScript[pos] == ';') {
|
||||
// The class declaration has ended and there are no
|
||||
// children
|
||||
currentClass.clear();
|
||||
pos += len;
|
||||
break;
|
||||
}
|
||||
|
||||
// Check next symbol
|
||||
pos += len;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if end of class
|
||||
if (currentClass != "" && token == "}") {
|
||||
currentClass = "";
|
||||
pos += len;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if namespace so the metadata for members can be gathered
|
||||
if (token == "namespace") {
|
||||
// Get the scope after "namespace". It can be composed of multiple
|
||||
// nested namespaces, e.g. A::B::C
|
||||
do {
|
||||
do {
|
||||
pos += len;
|
||||
t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
} while (t == asTC_COMMENT || t == asTC_WHITESPACE);
|
||||
|
||||
if (t == asTC_IDENTIFIER) {
|
||||
if (currentNamespace != "")
|
||||
currentNamespace += "::";
|
||||
currentNamespace += modifiedScript.mid(pos, len);
|
||||
}
|
||||
} while (
|
||||
t == asTC_IDENTIFIER ||
|
||||
(t == asTC_KEYWORD && modifiedScript.mid(pos, len) == "::"));
|
||||
|
||||
// Search until first { is encountered
|
||||
while (qsizetype(pos) < modifiedScript.length()) {
|
||||
engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
|
||||
// If start of namespace section encountered stop
|
||||
if (modifiedScript[pos] == '{') {
|
||||
pos += len;
|
||||
break;
|
||||
}
|
||||
|
||||
// Check next symbol
|
||||
pos += len;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if end of namespace
|
||||
if (currentNamespace != "" && token == "}") {
|
||||
auto found = currentNamespace.lastIndexOf("::");
|
||||
if (found >= 0) {
|
||||
currentNamespace.remove(found, currentNamespace.size() - found);
|
||||
} else {
|
||||
currentNamespace = "";
|
||||
}
|
||||
pos += len;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Is this the start of metadata?
|
||||
if (token == "[") {
|
||||
// Get the metadata string
|
||||
pos = ExtractMetadata(pos, metadata);
|
||||
|
||||
// Determine what this metadata is for
|
||||
int type;
|
||||
ExtractDeclaration(pos, name, declaration, type);
|
||||
|
||||
// Store away the declaration in a map for lookup after the build
|
||||
// has completed
|
||||
if (type > 0) {
|
||||
SMetadataDecl decl(metadata, name, declaration, type,
|
||||
currentClass, currentNamespace);
|
||||
foundDeclarations.push_back(decl);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
// Is this a preprocessor directive?
|
||||
if (token == "#" && (qsizetype(pos + 1) < modifiedScript.size())) {
|
||||
int start = pos++;
|
||||
|
||||
t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
if (t == asTC_IDENTIFIER) {
|
||||
token = modifiedScript.mid(pos, len);
|
||||
if (token == "include") {
|
||||
pos += len;
|
||||
t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
if (t == asTC_WHITESPACE) {
|
||||
pos += len;
|
||||
t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos,
|
||||
&len);
|
||||
}
|
||||
|
||||
if (t == asTC_VALUE && len > 2 &&
|
||||
(modifiedScript[pos] == '"' ||
|
||||
modifiedScript[pos] == '\'')) {
|
||||
// Get the include file
|
||||
QString includefile =
|
||||
modifiedScript.mid(pos + 1, len - 2);
|
||||
pos += len;
|
||||
|
||||
// Make sure the includeFile doesn't contain any
|
||||
// line breaks
|
||||
auto p = includefile.indexOf('\n');
|
||||
if (p >= 0) {
|
||||
// TODO: Show the correct line number for the
|
||||
// error
|
||||
auto str =
|
||||
QObject::tr("Invalid file name for #include; "
|
||||
"it contains a line-break: ") +
|
||||
QStringLiteral("'") + includefile.left(p) +
|
||||
QStringLiteral("'");
|
||||
engine->WriteMessage(sectionname.toUtf8(), 0, 0,
|
||||
asMSGTYPE_ERROR, str.toUtf8());
|
||||
} else {
|
||||
// Store it for later processing
|
||||
includes.append({includefile, true});
|
||||
|
||||
// Overwrite the include directive with space
|
||||
// characters to avoid compiler error
|
||||
OverwriteCode(start, pos - start);
|
||||
}
|
||||
}
|
||||
|
||||
if (t == asTC_KEYWORD && modifiedScript[pos] == '<') {
|
||||
pos += len;
|
||||
|
||||
// find the next '>'
|
||||
auto rpos = pos;
|
||||
bool found = false;
|
||||
for (; qsizetype(rpos) < modifiedScript.size();
|
||||
++rpos) {
|
||||
if (modifiedScript[rpos] == '>') {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if (modifiedScript[rpos] == '\n') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
QString includefile =
|
||||
modifiedScript.mid(pos, rpos - pos).trimmed();
|
||||
|
||||
pos = rpos + 1;
|
||||
|
||||
// Make sure the includeFile doesn't contain any
|
||||
// line breaks
|
||||
auto p = includefile.indexOf('\n');
|
||||
auto ws = includefile.indexOf(' ');
|
||||
if (!includefile.isEmpty() && p >= 0 && ws >= 0) {
|
||||
// TODO: Show the correct line number for
|
||||
// the error
|
||||
auto str =
|
||||
QObject::tr(
|
||||
"Invalid file name for #include; "
|
||||
"it contains a line-break: ") +
|
||||
QStringLiteral("'") + includefile.left(p) +
|
||||
QStringLiteral("'");
|
||||
engine->WriteMessage(sectionname.toUtf8(), 0, 0,
|
||||
asMSGTYPE_ERROR,
|
||||
str.toUtf8());
|
||||
} else {
|
||||
// Store it for later processing
|
||||
includes.append({includefile, false});
|
||||
|
||||
// Overwrite the include directive with
|
||||
// space characters to avoid compiler error
|
||||
OverwriteCode(start, pos - start);
|
||||
}
|
||||
} else {
|
||||
auto str =
|
||||
QObject::tr("Invalid file name for #include; "
|
||||
"it contains a line-break or "
|
||||
"unpaired symbol");
|
||||
engine->WriteMessage(sectionname.toUtf8(), 0, 0,
|
||||
asMSGTYPE_ERROR, str.toUtf8());
|
||||
}
|
||||
}
|
||||
} else if (token == "pragma") {
|
||||
// Read until the end of the line
|
||||
pos += len;
|
||||
for (; qsizetype(pos) < modifiedScript.size() &&
|
||||
modifiedScript[pos] != '\n';
|
||||
pos++)
|
||||
;
|
||||
|
||||
// Call the pragma callback
|
||||
auto pragmaText =
|
||||
modifiedScript.mid(start + 7, pos - start - 7);
|
||||
int r = pragmaCallback
|
||||
? pragmaCallback(pragmaText, this, pragmaParam)
|
||||
: -1;
|
||||
if (r < 0) {
|
||||
// TODO: Report the correct line number
|
||||
engine->WriteMessage(
|
||||
sectionname.toUtf8(), 0, 0, asMSGTYPE_ERROR,
|
||||
QObject::tr("Invalid #pragma directive").toUtf8());
|
||||
return r;
|
||||
}
|
||||
|
||||
// Overwrite the pragma directive with space characters
|
||||
// to avoid compiler error
|
||||
OverwriteCode(start, pos - start);
|
||||
}
|
||||
} else {
|
||||
// Check for lines starting with #!, e.g. shebang
|
||||
// interpreter directive. These will be treated as comments
|
||||
// and removed by the preprocessor
|
||||
if (modifiedScript[pos] == '!') {
|
||||
// Read until the end of the line
|
||||
pos += len;
|
||||
for (; qsizetype(pos) < modifiedScript.size() &&
|
||||
modifiedScript[pos] != '\n';
|
||||
pos++)
|
||||
;
|
||||
|
||||
// Overwrite the directive with space characters to
|
||||
// avoid compiler error
|
||||
OverwriteCode(start, pos - start);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Don't search for metadata/includes within statement blocks or
|
||||
// between tokens in statements
|
||||
else {
|
||||
pos = SkipStatement(pos);
|
||||
}
|
||||
}
|
||||
|
||||
// Build the actual script
|
||||
engine->SetEngineProperty(asEP_COPY_SCRIPT_SECTIONS, true);
|
||||
module->AddScriptSection(sectionname.toUtf8(), modifiedScript.data(),
|
||||
modifiedScript.size(), lineOffset);
|
||||
|
||||
if (includes.size() > 0) {
|
||||
// If the callback has been set, then call it for each included file
|
||||
if (includeCallback) {
|
||||
for (QVector<QString>::size_type n = 0; n < includes.size(); n++) {
|
||||
auto inc = includes[n];
|
||||
int r = includeCallback(inc.first, inc.second, sectionname,
|
||||
this, includeParam);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
// By default we try to load the included file from the relative
|
||||
// directory of the current file
|
||||
|
||||
// Determine the path of the current script so that we can resolve
|
||||
// relative paths for includes
|
||||
auto path = QFileInfo(sectionname).filePath();
|
||||
|
||||
// Load the included scripts
|
||||
for (QVector<QString>::size_type n = 0; n < includes.size(); n++) {
|
||||
// If the include is a relative path, then prepend the path of
|
||||
// the originating script
|
||||
|
||||
auto inc = includes.at(n);
|
||||
if (!QFileInfo(inc.first).isAbsolute()) {
|
||||
includes[n].first = path + QDir::separator() + inc.first;
|
||||
}
|
||||
|
||||
// Include the script section
|
||||
int r = AddSectionFromFile(includes[n].first);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int asBuilder::Build() {
|
||||
int r = module->Build();
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
#if AS_PROCESS_METADATA == 1
|
||||
// After the script has been built, the metadata strings should be
|
||||
// stored for later lookup by function id, type id, and variable index
|
||||
for (int n = 0; n < (int)foundDeclarations.size(); n++) {
|
||||
|
@ -764,289 +222,6 @@ int asBuilder::Build() {
|
|||
}
|
||||
}
|
||||
module->SetDefaultNamespace("");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int asBuilder::SkipStatement(int pos) {
|
||||
asUINT len = 0;
|
||||
|
||||
// Skip until ; or { whichever comes first
|
||||
while (pos < (int)modifiedScript.length() && modifiedScript[pos] != ';' &&
|
||||
modifiedScript[pos] != '{') {
|
||||
engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
pos += len;
|
||||
}
|
||||
|
||||
// Skip entire statement block
|
||||
if (pos < (int)modifiedScript.length() && modifiedScript[pos] == '{') {
|
||||
pos += 1;
|
||||
|
||||
// Find the end of the statement block
|
||||
int level = 1;
|
||||
while (level > 0 && pos < (int)modifiedScript.size()) {
|
||||
asETokenClass t = engine->ParseToken(
|
||||
modifiedScript.data() + pos, modifiedScript.size() - pos, &len);
|
||||
if (t == asTC_KEYWORD) {
|
||||
if (modifiedScript[pos] == '{')
|
||||
level++;
|
||||
else if (modifiedScript[pos] == '}')
|
||||
level--;
|
||||
}
|
||||
|
||||
pos += len;
|
||||
}
|
||||
} else
|
||||
pos += 1;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
// Overwrite all code with blanks until the matching #endif
|
||||
int asBuilder::ExcludeCode(int pos) {
|
||||
asUINT len = 0;
|
||||
int nested = 0;
|
||||
while (pos < (int)modifiedScript.size()) {
|
||||
engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
if (modifiedScript[pos] == '#') {
|
||||
modifiedScript[pos] = ' ';
|
||||
pos++;
|
||||
|
||||
// Is it an #if or #endif directive?
|
||||
engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
QString token = modifiedScript.mid(pos, len);
|
||||
OverwriteCode(pos, len);
|
||||
|
||||
if (token == "if") {
|
||||
nested++;
|
||||
} else if (token == "endif") {
|
||||
if (nested-- == 0) {
|
||||
pos += len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (modifiedScript[pos] != '\n') {
|
||||
OverwriteCode(pos, len);
|
||||
}
|
||||
pos += len;
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
// Overwrite all characters except line breaks with blanks
|
||||
void asBuilder::OverwriteCode(int start, int len) {
|
||||
auto code = modifiedScript.data() + start;
|
||||
for (int n = 0; n < len; n++) {
|
||||
if (*code != '\n')
|
||||
*code = ' ';
|
||||
code++;
|
||||
}
|
||||
}
|
||||
|
||||
#if AS_PROCESS_METADATA == 1
|
||||
int asBuilder::ExtractMetadata(int pos, QVector<QString> &metadata) {
|
||||
metadata.clear();
|
||||
|
||||
// Extract all metadata. They can be separated by whitespace and comments
|
||||
for (;;) {
|
||||
QString metadataString;
|
||||
|
||||
// Overwrite the metadata with space characters to allow compilation
|
||||
modifiedScript[pos] = ' ';
|
||||
|
||||
// Skip opening brackets
|
||||
pos += 1;
|
||||
|
||||
int level = 1;
|
||||
asUINT len = 0;
|
||||
while (level > 0 && pos < (int)modifiedScript.size()) {
|
||||
asETokenClass t = engine->ParseToken(
|
||||
modifiedScript.data() + pos, modifiedScript.size() - pos, &len);
|
||||
if (t == asTC_KEYWORD) {
|
||||
if (modifiedScript[pos] == '[')
|
||||
level++;
|
||||
else if (modifiedScript[pos] == ']')
|
||||
level--;
|
||||
}
|
||||
|
||||
// Copy the metadata to our buffer
|
||||
if (level > 0)
|
||||
metadataString.append(modifiedScript.mid(pos, len));
|
||||
|
||||
// Overwrite the metadata with space characters to allow compilation
|
||||
if (t != asTC_WHITESPACE)
|
||||
OverwriteCode(pos, len);
|
||||
|
||||
pos += len;
|
||||
}
|
||||
|
||||
metadata.push_back(metadataString);
|
||||
|
||||
// Check for more metadata. Possibly separated by comments
|
||||
asETokenClass t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
while (t == asTC_COMMENT || t == asTC_WHITESPACE) {
|
||||
pos += len;
|
||||
t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
}
|
||||
|
||||
if (modifiedScript[pos] != '[')
|
||||
break;
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
int asBuilder::ExtractDeclaration(int pos, QString &name, QString &declaration,
|
||||
int &type) {
|
||||
declaration.clear();
|
||||
type = 0;
|
||||
|
||||
int start = pos;
|
||||
|
||||
QString token;
|
||||
asUINT len = 0;
|
||||
asETokenClass t = asTC_WHITESPACE;
|
||||
|
||||
// Skip white spaces, comments, and leading decorators
|
||||
do {
|
||||
pos += len;
|
||||
t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
token = modifiedScript.mid(pos, len);
|
||||
} while (t == asTC_WHITESPACE || t == asTC_COMMENT || token == "private" ||
|
||||
token == "protected" || token == "shared" || token == "external" ||
|
||||
token == "final" || token == "abstract");
|
||||
|
||||
// We're expecting, either a class, interface, function, or variable
|
||||
// declaration
|
||||
if (t == asTC_KEYWORD || t == asTC_IDENTIFIER) {
|
||||
token = modifiedScript.mid(pos, len);
|
||||
if (token == "interface" || token == "class" || token == "enum") {
|
||||
// Skip white spaces and comments
|
||||
do {
|
||||
pos += len;
|
||||
t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
} while (t == asTC_WHITESPACE || t == asTC_COMMENT);
|
||||
|
||||
if (t == asTC_IDENTIFIER) {
|
||||
type = MDT_TYPE;
|
||||
declaration = modifiedScript.mid(pos, len);
|
||||
pos += len;
|
||||
return pos;
|
||||
}
|
||||
} else {
|
||||
// For function declarations, store everything up to the start of
|
||||
// the statement block, except for succeeding decorators (final,
|
||||
// override, etc)
|
||||
|
||||
// For variable declaration store just the name as there can only be
|
||||
// one
|
||||
|
||||
// We'll only know if the declaration is a variable or function
|
||||
// declaration when we see the statement block, or absense of a
|
||||
// statement block.
|
||||
bool hasParenthesis = false;
|
||||
int nestedParenthesis = 0;
|
||||
declaration.append(modifiedScript.mid(pos, len));
|
||||
pos += len;
|
||||
for (; pos < (int)modifiedScript.size();) {
|
||||
t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
token = modifiedScript.mid(pos, len);
|
||||
if (t == asTC_KEYWORD) {
|
||||
if (token == "{" && nestedParenthesis == 0) {
|
||||
if (hasParenthesis) {
|
||||
// We've found the end of a function signature
|
||||
type = MDT_FUNC;
|
||||
} else {
|
||||
// We've found a virtual property. Just keep the
|
||||
// name
|
||||
declaration = name;
|
||||
type = MDT_VIRTPROP;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
if ((token == "=" && !hasParenthesis) || token == ";") {
|
||||
if (hasParenthesis) {
|
||||
// The declaration is ambigous. It can be a variable
|
||||
// with initialization, or a function prototype
|
||||
type = MDT_FUNC_OR_VAR;
|
||||
} else {
|
||||
// Substitute the declaration with just the name
|
||||
declaration = name;
|
||||
type = MDT_VAR;
|
||||
}
|
||||
return pos;
|
||||
} else if (token == "(") {
|
||||
nestedParenthesis++;
|
||||
|
||||
// This is the first parenthesis we encounter. If the
|
||||
// parenthesis isn't followed by a statement block, then
|
||||
// this is a variable declaration, in which case we
|
||||
// should only store the type and name of the variable,
|
||||
// not the initialization parameters.
|
||||
hasParenthesis = true;
|
||||
} else if (token == ")") {
|
||||
nestedParenthesis--;
|
||||
}
|
||||
} else if (t == asTC_IDENTIFIER) {
|
||||
// If a parenthesis is already found then the name is
|
||||
// already known so it must not be overwritten
|
||||
if (!hasParenthesis)
|
||||
name = token;
|
||||
}
|
||||
|
||||
// Skip trailing decorators
|
||||
if (!hasParenthesis || nestedParenthesis > 0 ||
|
||||
t != asTC_IDENTIFIER ||
|
||||
(token != "final" && token != "override" &&
|
||||
token != "delete" && token != "property"))
|
||||
declaration += token;
|
||||
|
||||
pos += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
QVector<QString> asBuilder::GetMetadataForType(int typeId) {
|
||||
return typeMetadataMap.value(typeId);
|
||||
}
|
||||
|
||||
QVector<QString> asBuilder::GetMetadataForFunc(asIScriptFunction *func) {
|
||||
return funcMetadataMap.value(func->GetId());
|
||||
}
|
||||
|
||||
QVector<QString> asBuilder::GetMetadataForVar(int varIdx) {
|
||||
return varMetadataMap.value(varIdx);
|
||||
}
|
||||
|
||||
QVector<QString> asBuilder::GetMetadataForTypeProperty(int typeId, int varIdx) {
|
||||
if (classMetadataMap.contains(typeId)) {
|
||||
return varMetadataMap.value(varIdx);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
QVector<QString>
|
||||
asBuilder::GetMetadataForTypeMethod(int typeId, asIScriptFunction *method) {
|
||||
if (method) {
|
||||
if (classMetadataMap.contains(typeId)) {
|
||||
return funcMetadataMap.value(method->GetId());
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
#endif
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
|
|
@ -18,198 +18,27 @@
|
|||
#ifndef ASBUILDER_H
|
||||
#define ASBUILDER_H
|
||||
|
||||
//---------------------------
|
||||
// Compilation settings
|
||||
//
|
||||
|
||||
// Set this flag to turn on/off metadata processing
|
||||
// 0 = off
|
||||
// 1 = on
|
||||
#ifndef AS_PROCESS_METADATA
|
||||
#define AS_PROCESS_METADATA 1
|
||||
#endif
|
||||
|
||||
// TODO: Implement flags for turning on/off include directives and conditional
|
||||
// programming
|
||||
|
||||
//---------------------------
|
||||
// Declaration
|
||||
//
|
||||
|
||||
#ifndef ANGELSCRIPT_H
|
||||
// Avoid having to inform include path if header is already include before
|
||||
#include <angelscript.h>
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1200
|
||||
// disable the annoying warnings on MSVC 6
|
||||
#pragma warning(disable : 4786)
|
||||
#endif
|
||||
#include "aspreprocesser.h"
|
||||
|
||||
#include <QMap>
|
||||
#include <QSet>
|
||||
#include <QVector>
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
class asBuilder;
|
||||
|
||||
// This callback will be called for each #include directive encountered by the
|
||||
// builder. The callback should call the AddSectionFromFile or
|
||||
// AddSectionFromMemory to add the included section to the script. If the
|
||||
// include cannot be resolved then the function should return a negative value
|
||||
// to abort the compilation.
|
||||
typedef int (*INCLUDECALLBACK_t)(const QString &include, bool quotedInclude,
|
||||
const QString &from, asBuilder *builder,
|
||||
void *userParam);
|
||||
|
||||
// This callback will be called for each #pragma directive encountered by the
|
||||
// builder. The application can interpret the pragmaText and decide what do to
|
||||
// based on that. If the callback returns a negative value the builder will
|
||||
// report an error and abort the compilation.
|
||||
typedef int (*PRAGMACALLBACK_t)(const QByteArray &pragmaText,
|
||||
asBuilder *builder, void *userParam);
|
||||
|
||||
// Helper class for loading and pre-processing script files to
|
||||
// support include directives and metadata declarations
|
||||
|
||||
class asBuilder {
|
||||
class asBuilder : public AsPreprocesser {
|
||||
public:
|
||||
explicit asBuilder();
|
||||
explicit asBuilder(asIScriptEngine *engine);
|
||||
|
||||
// Start a new module
|
||||
int StartNewModule(asIScriptEngine *engine, const char *moduleName);
|
||||
|
||||
// Load a script section from a file on disk
|
||||
// Returns 1 if the file was included
|
||||
// 0 if the file had already been included before
|
||||
// <0 on error
|
||||
int AddSectionFromFile(const QString &filename);
|
||||
|
||||
// Load a script section from memory
|
||||
// Returns 1 if the section was included
|
||||
// 0 if a section with the same name had already been included
|
||||
// before
|
||||
// <0 on error
|
||||
int AddSectionFromMemory(const char *sectionName, const char *scriptCode,
|
||||
unsigned int scriptLength = 0, int lineOffset = 0);
|
||||
int StartNewModule(const char *moduleName);
|
||||
|
||||
// Build the added script sections
|
||||
int BuildModule();
|
||||
|
||||
// Returns the engine
|
||||
asIScriptEngine *GetEngine();
|
||||
int Build();
|
||||
|
||||
// Returns the current module
|
||||
asIScriptModule *GetModule();
|
||||
|
||||
// Register the callback for resolving include directive
|
||||
void SetIncludeCallback(INCLUDECALLBACK_t callback, void *userParam);
|
||||
|
||||
// Register the callback for resolving pragma directive
|
||||
void SetPragmaCallback(PRAGMACALLBACK_t callback, void *userParam);
|
||||
|
||||
// Add a pre-processor define for conditional compilation
|
||||
void DefineWord(const QString &word);
|
||||
|
||||
// Enumerate included script sections
|
||||
unsigned int GetSectionCount() const;
|
||||
|
||||
QString GetSectionName(unsigned int idx) const;
|
||||
|
||||
#if AS_PROCESS_METADATA == 1
|
||||
// Get metadata declared for classes, interfaces, and enums
|
||||
QVector<QString> GetMetadataForType(int typeId);
|
||||
|
||||
// Get metadata declared for functions
|
||||
QVector<QString> GetMetadataForFunc(asIScriptFunction *func);
|
||||
|
||||
// Get metadata declared for global variables
|
||||
QVector<QString> GetMetadataForVar(int varIdx);
|
||||
|
||||
// Get metadata declared for class variables
|
||||
QVector<QString> GetMetadataForTypeProperty(int typeId, int varIdx);
|
||||
|
||||
// Get metadata declared for class methods
|
||||
QVector<QString> GetMetadataForTypeMethod(int typeId,
|
||||
asIScriptFunction *method);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
void ClearAll();
|
||||
int Build();
|
||||
int ProcessScriptSection(const QByteArray &script, int length,
|
||||
const QString §ionname, int lineOffset);
|
||||
int LoadScriptSection(const QString &filename);
|
||||
bool IncludeIfNotAlreadyIncluded(const QString &filename);
|
||||
|
||||
int SkipStatement(int pos);
|
||||
|
||||
int ExcludeCode(int start);
|
||||
void OverwriteCode(int start, int len);
|
||||
|
||||
asIScriptEngine *engine;
|
||||
asIScriptModule *module;
|
||||
QByteArray modifiedScript;
|
||||
|
||||
INCLUDECALLBACK_t includeCallback;
|
||||
void *includeParam;
|
||||
|
||||
PRAGMACALLBACK_t pragmaCallback;
|
||||
void *pragmaParam;
|
||||
|
||||
#if AS_PROCESS_METADATA == 1
|
||||
int ExtractMetadata(int pos, QVector<QString> &outMetadata);
|
||||
int ExtractDeclaration(int pos, QString &outName, QString &outDeclaration,
|
||||
int &outType);
|
||||
|
||||
enum METADATATYPE {
|
||||
MDT_TYPE = 1,
|
||||
MDT_FUNC = 2,
|
||||
MDT_VAR = 3,
|
||||
MDT_VIRTPROP = 4,
|
||||
MDT_FUNC_OR_VAR = 5
|
||||
};
|
||||
|
||||
// Temporary structure for storing metadata and declaration
|
||||
struct SMetadataDecl {
|
||||
SMetadataDecl(const QVector<QString> &m, const QString &n,
|
||||
const QString &d, int t, const QString &c,
|
||||
const QString &ns)
|
||||
: metadata(m), name(n), declaration(d), type(t), parentClass(c),
|
||||
nameSpace(ns) {}
|
||||
QVector<QString> metadata;
|
||||
QString name;
|
||||
QString declaration;
|
||||
int type;
|
||||
QString parentClass;
|
||||
QString nameSpace;
|
||||
};
|
||||
QVector<SMetadataDecl> foundDeclarations;
|
||||
QString currentClass;
|
||||
QString currentNamespace;
|
||||
|
||||
// Storage of metadata for global declarations
|
||||
QMap<int, QVector<QString>> typeMetadataMap;
|
||||
QMap<int, QVector<QString>> funcMetadataMap;
|
||||
QMap<int, QVector<QString>> varMetadataMap;
|
||||
|
||||
// Storage of metadata for class member declarations
|
||||
struct SClassMetadata {
|
||||
SClassMetadata(const QString &aName) : className(aName) {}
|
||||
QString className;
|
||||
QMap<int, QVector<QString>> funcMetadataMap;
|
||||
QMap<int, QVector<QString>> varMetadataMap;
|
||||
};
|
||||
QMap<int, SClassMetadata> classMetadataMap;
|
||||
|
||||
#endif
|
||||
|
||||
QVector<QString> includedScripts;
|
||||
|
||||
QVector<QString> definedWords;
|
||||
};
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif // ASBUILDER_H
|
||||
|
|
|
@ -32,9 +32,9 @@
|
|||
|
||||
#include "control/qcodecompletionwidget.h"
|
||||
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QString, DOT_TRIGGER, ("."))
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QString, SEMI_COLON_TRIGGER, ("::"))
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QString, LEFT_PARE_TRIGGER, ("("))
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, DOT_TRIGGER, ("."))
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, SEMI_COLON_TRIGGER, ("::"))
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, LEFT_PARE_TRIGGER, ("("))
|
||||
|
||||
AsCompletion::AsCompletion(asIScriptEngine *engine, QObject *p)
|
||||
: QCodeCompletionEngine(p), parser(engine), _engine(engine),
|
||||
|
@ -47,8 +47,6 @@ AsCompletion::AsCompletion(asIScriptEngine *engine, QObject *p)
|
|||
// unleash the power of call tips
|
||||
addTrigger(*LEFT_PARE_TRIGGER);
|
||||
|
||||
// TODO parse the std aslib
|
||||
|
||||
setTrigWordLen(3);
|
||||
}
|
||||
|
||||
|
@ -77,16 +75,27 @@ QStringList AsCompletion::extensions() const {
|
|||
}
|
||||
|
||||
void AsCompletion::complete(const QDocumentCursor &c, const QString &trigger) {
|
||||
// TODO parse current code
|
||||
// auto codes = c.document()->text(true, false);
|
||||
// parser.parse(codes, this->editor()->fileName());
|
||||
|
||||
// QList<QCodeNode *> nodes = parser.codeNodes();
|
||||
auto txt = c.line().text();
|
||||
if (txt.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
auto code = txt.left(c.columnNumber()).toUtf8();
|
||||
|
||||
auto off = 0;
|
||||
auto offcur = c.document()->property("console");
|
||||
if (!offcur.isNull() && offcur.isValid()) {
|
||||
auto cur = offcur.value<QDocumentCursor>();
|
||||
if (cur.isValid()) {
|
||||
off = cur.columnNumber();
|
||||
}
|
||||
} else {
|
||||
// TODO parse current code
|
||||
auto codes = c.document()->text(true, false);
|
||||
parser.parse(codes, this->editor()->fileName());
|
||||
|
||||
// QList<QCodeNode *> nodes = parser.codeNodes();
|
||||
}
|
||||
|
||||
auto code = txt.mid(off, c.columnNumber() - off).toUtf8();
|
||||
|
||||
auto p = code.data();
|
||||
auto len = code.length();
|
||||
|
@ -98,6 +107,7 @@ void AsCompletion::complete(const QDocumentCursor &c, const QString &trigger) {
|
|||
QByteArray content;
|
||||
};
|
||||
|
||||
// parse the tokens
|
||||
QVector<Token> tokens;
|
||||
qsizetype pos = 0;
|
||||
for (; p < end;) {
|
||||
|
@ -112,9 +122,6 @@ void AsCompletion::complete(const QDocumentCursor &c, const QString &trigger) {
|
|||
pos += tokenLen;
|
||||
}
|
||||
|
||||
QByteArray fn;
|
||||
QList<QCodeNode *> nodes;
|
||||
|
||||
auto r =
|
||||
std::find_if(tokens.rbegin(), tokens.rend(), [](const Token &token) {
|
||||
return token.type != asTC_WHITESPACE;
|
||||
|
@ -123,10 +130,12 @@ void AsCompletion::complete(const QDocumentCursor &c, const QString &trigger) {
|
|||
return;
|
||||
}
|
||||
|
||||
QByteArray fn;
|
||||
QList<QCodeNode *> nodes;
|
||||
|
||||
QCodeCompletionWidget::Filter filter =
|
||||
QCodeCompletionWidget::FilterFlag::KeepAll;
|
||||
auto &_headerNodes = parser.headerNodes();
|
||||
fn = r->content;
|
||||
|
||||
if (trigger.isEmpty() && trigWordLen() <= r->content.length()) {
|
||||
auto eb = tokens.back();
|
||||
|
@ -141,36 +150,46 @@ void AsCompletion::complete(const QDocumentCursor &c, const QString &trigger) {
|
|||
}
|
||||
return;
|
||||
} else if (eb.type == asTC_IDENTIFIER) {
|
||||
if (r != tokens.rend()) {
|
||||
auto pr = std::next(r);
|
||||
if (pr != tokens.rend()) {
|
||||
if (pr->content == *SEMI_COLON_TRIGGER) {
|
||||
if (pr != tokens.rend()) {
|
||||
auto prr = std::next(pr);
|
||||
auto ns = prr->content;
|
||||
fn = eb.content;
|
||||
|
||||
if (prr->type == asTC_IDENTIFIER) {
|
||||
for (auto &n : _headerNodes) {
|
||||
auto name = n->qualifiedName();
|
||||
if (name == ns) {
|
||||
nodes << n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// completion for a.b.c or a::b.c or a::b::c.d or ::a::b.c
|
||||
// first validate
|
||||
auto rbegin = tokens.rbegin();
|
||||
auto rend = tokens.rend();
|
||||
|
||||
rbegin++;
|
||||
if (rbegin == rend) {
|
||||
applyEmptyNsNode(nodes);
|
||||
} else {
|
||||
if (rbegin->content == SEMI_COLON_TRIGGER) {
|
||||
QByteArrayList nss;
|
||||
bool semiFlag = true;
|
||||
auto p = rbegin;
|
||||
for (; p != rend; ++p) {
|
||||
if (semiFlag) {
|
||||
if (p->type != asTC_IDENTIFIER) {
|
||||
break;
|
||||
} else {
|
||||
return;
|
||||
nss.prepend(p->content);
|
||||
semiFlag = false;
|
||||
}
|
||||
} else {
|
||||
applyEmptyNsNode(nodes);
|
||||
if (p->content != SEMI_COLON_TRIGGER) {
|
||||
break;
|
||||
}
|
||||
semiFlag = true;
|
||||
}
|
||||
} else {
|
||||
applyEmptyNsNode(nodes);
|
||||
}
|
||||
|
||||
nodes = lookupNamespace(nss);
|
||||
if (nodes.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
} else if (rbegin->content == DOT_TRIGGER) {
|
||||
// TODO
|
||||
} else {
|
||||
applyEmptyNsNode(nodes);
|
||||
}
|
||||
} else {
|
||||
applyEmptyNsNode(nodes);
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
|
@ -183,13 +202,32 @@ void AsCompletion::complete(const QDocumentCursor &c, const QString &trigger) {
|
|||
pPopup->popup();
|
||||
} else {
|
||||
if (trigger == *SEMI_COLON_TRIGGER) {
|
||||
for (auto &n : _headerNodes) {
|
||||
auto name = n->qualifiedName();
|
||||
if (name == fn) {
|
||||
nodes << n;
|
||||
break;
|
||||
auto rbegin = tokens.rbegin();
|
||||
auto rend = tokens.rend();
|
||||
|
||||
QByteArrayList nss;
|
||||
bool semiFlag = true;
|
||||
auto p = rbegin;
|
||||
for (; p != rend; ++p) {
|
||||
if (semiFlag) {
|
||||
if (p->type != asTC_IDENTIFIER) {
|
||||
break;
|
||||
} else {
|
||||
nss.prepend(p->content);
|
||||
semiFlag = false;
|
||||
}
|
||||
} else {
|
||||
if (p->content != *SEMI_COLON_TRIGGER) {
|
||||
break;
|
||||
}
|
||||
semiFlag = true;
|
||||
}
|
||||
}
|
||||
|
||||
nodes = lookupNamespace(nss);
|
||||
if (nodes.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
} else if (trigger == *LEFT_PARE_TRIGGER) {
|
||||
if (r != tokens.rend()) {
|
||||
auto pr = std::next(r);
|
||||
|
@ -274,7 +312,7 @@ void AsCompletion::complete(const QDocumentCursor &c, const QString &trigger) {
|
|||
}
|
||||
} else {
|
||||
// qDeleteAll(temp);
|
||||
qDebug("completion failed");
|
||||
// qDebug("completion failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -286,6 +324,7 @@ void AsCompletion::applyEmptyNsNode(QList<QCodeNode *> &nodes) {
|
|||
if (name.isEmpty()) {
|
||||
// only one group for empty namespace
|
||||
_emptyNsNodes << n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -293,6 +332,47 @@ void AsCompletion::applyEmptyNsNode(QList<QCodeNode *> &nodes) {
|
|||
nodes = _emptyNsNodes;
|
||||
}
|
||||
|
||||
void AsCompletion::parse(const QDocumentCursor &c) {
|
||||
auto codes = c.document()->text();
|
||||
// asBuilder builder;
|
||||
}
|
||||
|
||||
QList<QCodeNode *> AsCompletion::lookupNamespace(const QByteArrayList &ns) {
|
||||
QList<QCodeNode *> nodes;
|
||||
|
||||
if (ns.isEmpty()) {
|
||||
return nodes;
|
||||
}
|
||||
|
||||
auto headers = parser.headerNodes();
|
||||
auto r =
|
||||
std::find_if(headers.begin(), headers.end(), [&ns](QCodeNode *node) {
|
||||
return node->role(QCodeNode::Name) == ns.first();
|
||||
});
|
||||
if (r != headers.end()) {
|
||||
auto n = *r;
|
||||
auto len = ns.size();
|
||||
|
||||
bool found = true;
|
||||
for (qsizetype i = 1; i < len; ++i) {
|
||||
auto &c = n->children();
|
||||
r = std::find_if(c.begin(), c.end(), [&ns, i](QCodeNode *node) {
|
||||
return node->role(QCodeNode::Name) == ns.at(i);
|
||||
});
|
||||
if (r == c.end()) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
nodes.append(*r);
|
||||
}
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
QCodeCompletionWidget *AsCompletion::codeCompletionWidget() const {
|
||||
return pPopup;
|
||||
}
|
||||
|
|
|
@ -47,6 +47,10 @@ protected:
|
|||
private:
|
||||
void applyEmptyNsNode(QList<QCodeNode *> &nodes);
|
||||
|
||||
void parse(const QDocumentCursor &c);
|
||||
|
||||
QList<QCodeNode *> lookupNamespace(const QByteArrayList &ns);
|
||||
|
||||
private:
|
||||
QAsParser parser;
|
||||
asIScriptEngine *_engine;
|
||||
|
|
|
@ -0,0 +1,853 @@
|
|||
/*==============================================================================
|
||||
** 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 "aspreprocesser.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
|
||||
AsPreprocesser::AsPreprocesser(asIScriptEngine *engine) : engine(engine) {
|
||||
Q_ASSERT(engine);
|
||||
|
||||
includeCallback = nullptr;
|
||||
includeParam = nullptr;
|
||||
|
||||
pragmaCallback = nullptr;
|
||||
pragmaParam = nullptr;
|
||||
}
|
||||
|
||||
AsPreprocesser::~AsPreprocesser() { void ClearAll(); }
|
||||
|
||||
int AsPreprocesser::AddSectionFromFile(const QString &filename) {
|
||||
// The file name stored in the set should be the fully resolved name because
|
||||
// it is possible to name the same file in multiple ways using relative
|
||||
// paths.
|
||||
auto fullpath = QFileInfo(filename).absoluteFilePath();
|
||||
|
||||
if (IncludeIfNotAlreadyIncluded(fullpath)) {
|
||||
int r = LoadScriptSection(fullpath);
|
||||
if (r < 0)
|
||||
return r;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AsPreprocesser::AddSectionFromMemory(const QString §ionName,
|
||||
const QByteArray &code,
|
||||
int lineOffset) {
|
||||
if (IncludeIfNotAlreadyIncluded(sectionName)) {
|
||||
int r = ProcessScriptSection(code, 0, sectionName, lineOffset);
|
||||
if (r < 0)
|
||||
return r;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
QList<AsPreprocesser::ScriptData> AsPreprocesser::GetScriptData() const {
|
||||
return modifiedScripts;
|
||||
}
|
||||
|
||||
asIScriptEngine *AsPreprocesser::GetEngine() { return engine; }
|
||||
|
||||
void AsPreprocesser::SetIncludeCallback(INCLUDECALLBACK_t callback,
|
||||
void *userParam) {
|
||||
includeCallback = callback;
|
||||
includeParam = userParam;
|
||||
}
|
||||
|
||||
void AsPreprocesser::SetPragmaCallback(PRAGMACALLBACK_t callback,
|
||||
void *userParam) {
|
||||
pragmaCallback = callback;
|
||||
pragmaParam = userParam;
|
||||
}
|
||||
|
||||
void AsPreprocesser::DefineWord(const QString &word) {
|
||||
if (!definedWords.contains(word)) {
|
||||
definedWords.append(word);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int AsPreprocesser::GetSectionCount() const {
|
||||
return (unsigned int)(includedScripts.size());
|
||||
}
|
||||
|
||||
QString AsPreprocesser::GetSectionName(unsigned int idx) const {
|
||||
if (qsizetype(idx) >= qsizetype(includedScripts.size()))
|
||||
return {};
|
||||
|
||||
return includedScripts.at(idx);
|
||||
}
|
||||
|
||||
QVector<QString> AsPreprocesser::GetMetadataForType(int typeId) {
|
||||
return typeMetadataMap.value(typeId);
|
||||
}
|
||||
|
||||
QVector<QString> AsPreprocesser::GetMetadataForFunc(asIScriptFunction *func) {
|
||||
return funcMetadataMap.value(func->GetId());
|
||||
}
|
||||
|
||||
QVector<QString> AsPreprocesser::GetMetadataForVar(int varIdx) {
|
||||
return varMetadataMap.value(varIdx);
|
||||
}
|
||||
|
||||
QVector<QString> AsPreprocesser::GetMetadataForTypeProperty(int typeId,
|
||||
int varIdx) {
|
||||
if (classMetadataMap.contains(typeId)) {
|
||||
return varMetadataMap.value(varIdx);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
QVector<QString>
|
||||
AsPreprocesser::GetMetadataForTypeMethod(int typeId,
|
||||
asIScriptFunction *method) {
|
||||
if (method) {
|
||||
if (classMetadataMap.contains(typeId)) {
|
||||
return funcMetadataMap.value(method->GetId());
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void AsPreprocesser::ClearAll() {
|
||||
includedScripts.clear();
|
||||
|
||||
currentClass.clear();
|
||||
currentNamespace.clear();
|
||||
|
||||
foundDeclarations.clear();
|
||||
typeMetadataMap.clear();
|
||||
funcMetadataMap.clear();
|
||||
varMetadataMap.clear();
|
||||
}
|
||||
|
||||
int AsPreprocesser::ProcessScriptSection(const QByteArray &script, int length,
|
||||
const QString §ionname,
|
||||
int lineOffset) {
|
||||
QVector<QPair<QString, bool>> includes;
|
||||
|
||||
QByteArray modifiedScript;
|
||||
|
||||
// Perform a superficial parsing of the script first to store the metadata
|
||||
if (length)
|
||||
modifiedScript = script.left(length);
|
||||
else
|
||||
modifiedScript = script;
|
||||
|
||||
// First perform the checks for #if directives to exclude code that
|
||||
// shouldn't be compiled
|
||||
unsigned int pos = 0;
|
||||
int nested = 0;
|
||||
while (qsizetype(pos) < modifiedScript.size()) {
|
||||
asUINT len = 0;
|
||||
asETokenClass t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
if (t == asTC_UNKNOWN && modifiedScript[pos] == '#' &&
|
||||
(qsizetype(pos) + 1 < modifiedScript.size())) {
|
||||
int start = pos++;
|
||||
|
||||
// Is this an #if directive?
|
||||
t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
Q_UNUSED(t);
|
||||
|
||||
QByteArray token = modifiedScript.mid(pos, len);
|
||||
pos += len;
|
||||
|
||||
if (token == "if") {
|
||||
t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
if (t == asTC_WHITESPACE) {
|
||||
pos += len;
|
||||
t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
}
|
||||
|
||||
if (t == asTC_IDENTIFIER) {
|
||||
QByteArray word = modifiedScript.mid(pos, len);
|
||||
|
||||
// Overwrite the #if directive with space characters to
|
||||
// avoid compiler error
|
||||
pos += len;
|
||||
OverwriteCode(modifiedScript, start, pos - start);
|
||||
|
||||
// Has this identifier been defined by the application or
|
||||
// not?
|
||||
if (!definedWords.contains(word)) {
|
||||
// Exclude all the code until and including the #endif
|
||||
pos = ExcludeCode(modifiedScript, pos);
|
||||
} else {
|
||||
nested++;
|
||||
}
|
||||
}
|
||||
} else if (token == "endif") {
|
||||
// Only remove the #endif if there was a matching #if
|
||||
if (nested > 0) {
|
||||
OverwriteCode(modifiedScript, start, pos - start);
|
||||
nested--;
|
||||
}
|
||||
}
|
||||
} else
|
||||
pos += len;
|
||||
}
|
||||
|
||||
// Preallocate memory
|
||||
QString name, declaration;
|
||||
QVector<QString> metadata;
|
||||
declaration.reserve(100);
|
||||
|
||||
// Then check for meta data and pre-processor directives
|
||||
pos = 0;
|
||||
while (qsizetype(pos) < modifiedScript.size()) {
|
||||
asUINT len = 0;
|
||||
asETokenClass t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
if (t == asTC_COMMENT || t == asTC_WHITESPACE) {
|
||||
pos += len;
|
||||
continue;
|
||||
}
|
||||
QString token = modifiedScript.mid(pos, len);
|
||||
|
||||
// Skip possible decorators before class and interface declarations
|
||||
if (token == "shared" || token == "abstract" || token == "mixin" ||
|
||||
token == "external") {
|
||||
pos += len;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if class or interface so the metadata for members can be
|
||||
// gathered
|
||||
if (currentClass.isEmpty() &&
|
||||
(token == "class" || token == "interface")) {
|
||||
// Get the identifier after "class"
|
||||
do {
|
||||
pos += len;
|
||||
if (qsizetype(pos) >= modifiedScript.size()) {
|
||||
t = asTC_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
} while (t == asTC_COMMENT || t == asTC_WHITESPACE);
|
||||
|
||||
if (t == asTC_IDENTIFIER) {
|
||||
currentClass = modifiedScript.mid(pos, len);
|
||||
|
||||
// Search until first { or ; is encountered
|
||||
while (qsizetype(pos) < modifiedScript.length()) {
|
||||
engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
|
||||
// If start of class section encountered stop
|
||||
if (modifiedScript[pos] == '{') {
|
||||
pos += len;
|
||||
break;
|
||||
} else if (modifiedScript[pos] == ';') {
|
||||
// The class declaration has ended and there are no
|
||||
// children
|
||||
currentClass.clear();
|
||||
pos += len;
|
||||
break;
|
||||
}
|
||||
|
||||
// Check next symbol
|
||||
pos += len;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if end of class
|
||||
if (currentClass != "" && token == "}") {
|
||||
currentClass = "";
|
||||
pos += len;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if namespace so the metadata for members can be gathered
|
||||
if (token == "namespace") {
|
||||
// Get the scope after "namespace". It can be composed of multiple
|
||||
// nested namespaces, e.g. A::B::C
|
||||
do {
|
||||
do {
|
||||
pos += len;
|
||||
t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
} while (t == asTC_COMMENT || t == asTC_WHITESPACE);
|
||||
|
||||
if (t == asTC_IDENTIFIER) {
|
||||
if (currentNamespace != "")
|
||||
currentNamespace += "::";
|
||||
currentNamespace += modifiedScript.mid(pos, len);
|
||||
}
|
||||
} while (
|
||||
t == asTC_IDENTIFIER ||
|
||||
(t == asTC_KEYWORD && modifiedScript.mid(pos, len) == "::"));
|
||||
|
||||
// Search until first { is encountered
|
||||
while (qsizetype(pos) < modifiedScript.length()) {
|
||||
engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
|
||||
// If start of namespace section encountered stop
|
||||
if (modifiedScript[pos] == '{') {
|
||||
pos += len;
|
||||
break;
|
||||
}
|
||||
|
||||
// Check next symbol
|
||||
pos += len;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if end of namespace
|
||||
if (currentNamespace != "" && token == "}") {
|
||||
auto found = currentNamespace.lastIndexOf("::");
|
||||
if (found >= 0) {
|
||||
currentNamespace.remove(found, currentNamespace.size() - found);
|
||||
} else {
|
||||
currentNamespace = "";
|
||||
}
|
||||
pos += len;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Is this the start of metadata?
|
||||
if (token == "[") {
|
||||
// Get the metadata string
|
||||
pos = ExtractMetadata(modifiedScript, pos, metadata);
|
||||
|
||||
// Determine what this metadata is for
|
||||
int type;
|
||||
ExtractDeclaration(modifiedScript, pos, name, declaration, type);
|
||||
|
||||
// Store away the declaration in a map for lookup after the build
|
||||
// has completed
|
||||
if (type > 0) {
|
||||
SMetadataDecl decl(metadata, name, declaration, type,
|
||||
currentClass, currentNamespace);
|
||||
foundDeclarations.push_back(decl);
|
||||
}
|
||||
} else
|
||||
|
||||
// Is this a preprocessor directive?
|
||||
if (token == "#" && (qsizetype(pos + 1) < modifiedScript.size())) {
|
||||
int start = pos++;
|
||||
|
||||
t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
if (t == asTC_IDENTIFIER) {
|
||||
token = modifiedScript.mid(pos, len);
|
||||
if (token == "include") {
|
||||
pos += len;
|
||||
t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
if (t == asTC_WHITESPACE) {
|
||||
pos += len;
|
||||
t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos,
|
||||
&len);
|
||||
}
|
||||
|
||||
if (t == asTC_VALUE && len > 2 &&
|
||||
(modifiedScript[pos] == '"' ||
|
||||
modifiedScript[pos] == '\'')) {
|
||||
// Get the include file
|
||||
QString includefile =
|
||||
modifiedScript.mid(pos + 1, len - 2);
|
||||
pos += len;
|
||||
|
||||
// Make sure the includeFile doesn't contain any
|
||||
// line breaks
|
||||
auto p = includefile.indexOf('\n');
|
||||
if (p >= 0) {
|
||||
// TODO: Show the correct line number for the
|
||||
// error
|
||||
auto str =
|
||||
QObject::tr("Invalid file name for #include; "
|
||||
"it contains a line-break: ") +
|
||||
QStringLiteral("'") + includefile.left(p) +
|
||||
QStringLiteral("'");
|
||||
engine->WriteMessage(sectionname.toUtf8(), 0, 0,
|
||||
asMSGTYPE_ERROR, str.toUtf8());
|
||||
} else {
|
||||
// Store it for later processing
|
||||
includes.append({includefile, true});
|
||||
|
||||
// Overwrite the include directive with space
|
||||
// characters to avoid compiler error
|
||||
OverwriteCode(modifiedScript, start, pos - start);
|
||||
}
|
||||
}
|
||||
|
||||
if (t == asTC_KEYWORD && modifiedScript[pos] == '<') {
|
||||
pos += len;
|
||||
|
||||
// find the next '>'
|
||||
auto rpos = pos;
|
||||
bool found = false;
|
||||
for (; qsizetype(rpos) < modifiedScript.size();
|
||||
++rpos) {
|
||||
if (modifiedScript[rpos] == '>') {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if (modifiedScript[rpos] == '\n') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
QString includefile =
|
||||
modifiedScript.mid(pos, rpos - pos).trimmed();
|
||||
|
||||
pos = rpos + 1;
|
||||
|
||||
// Make sure the includeFile doesn't contain any
|
||||
// line breaks
|
||||
auto p = includefile.indexOf('\n');
|
||||
auto ws = includefile.indexOf(' ');
|
||||
if (!includefile.isEmpty() && p >= 0 && ws >= 0) {
|
||||
// TODO: Show the correct line number for
|
||||
// the error
|
||||
auto str =
|
||||
QObject::tr(
|
||||
"Invalid file name for #include; "
|
||||
"it contains a line-break: ") +
|
||||
QStringLiteral("'") + includefile.left(p) +
|
||||
QStringLiteral("'");
|
||||
engine->WriteMessage(sectionname.toUtf8(), 0, 0,
|
||||
asMSGTYPE_ERROR,
|
||||
str.toUtf8());
|
||||
} else {
|
||||
// Store it for later processing
|
||||
includes.append({includefile, false});
|
||||
|
||||
// Overwrite the include directive with
|
||||
// space characters to avoid compiler error
|
||||
OverwriteCode(modifiedScript, start,
|
||||
pos - start);
|
||||
}
|
||||
} else {
|
||||
auto str =
|
||||
QObject::tr("Invalid file name for #include; "
|
||||
"it contains a line-break or "
|
||||
"unpaired symbol");
|
||||
engine->WriteMessage(sectionname.toUtf8(), 0, 0,
|
||||
asMSGTYPE_ERROR, str.toUtf8());
|
||||
}
|
||||
}
|
||||
} else if (token == "pragma") {
|
||||
// Read until the end of the line
|
||||
pos += len;
|
||||
for (; qsizetype(pos) < modifiedScript.size() &&
|
||||
modifiedScript[pos] != '\n';
|
||||
pos++)
|
||||
;
|
||||
|
||||
// Call the pragma callback
|
||||
auto pragmaText =
|
||||
modifiedScript.mid(start + 7, pos - start - 7);
|
||||
int r = pragmaCallback
|
||||
? pragmaCallback(pragmaText, this, pragmaParam)
|
||||
: -1;
|
||||
if (r < 0) {
|
||||
// TODO: Report the correct line number
|
||||
engine->WriteMessage(
|
||||
sectionname.toUtf8(), 0, 0, asMSGTYPE_ERROR,
|
||||
QObject::tr("Invalid #pragma directive").toUtf8());
|
||||
return r;
|
||||
}
|
||||
|
||||
// Overwrite the pragma directive with space characters
|
||||
// to avoid compiler error
|
||||
OverwriteCode(modifiedScript, start, pos - start);
|
||||
}
|
||||
} else {
|
||||
// Check for lines starting with #!, e.g. shebang
|
||||
// interpreter directive. These will be treated as comments
|
||||
// and removed by the preprocessor
|
||||
if (modifiedScript[pos] == '!') {
|
||||
// Read until the end of the line
|
||||
pos += len;
|
||||
for (; qsizetype(pos) < modifiedScript.size() &&
|
||||
modifiedScript[pos] != '\n';
|
||||
pos++)
|
||||
;
|
||||
|
||||
// Overwrite the directive with space characters to
|
||||
// avoid compiler error
|
||||
OverwriteCode(modifiedScript, start, pos - start);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Don't search for metadata/includes within statement blocks or
|
||||
// between tokens in statements
|
||||
else {
|
||||
pos = SkipStatement(modifiedScript, pos);
|
||||
}
|
||||
}
|
||||
|
||||
// Build the actual script
|
||||
engine->SetEngineProperty(asEP_COPY_SCRIPT_SECTIONS, true);
|
||||
|
||||
AddScriptSection(sectionname, modifiedScript, lineOffset);
|
||||
|
||||
if (includes.size() > 0) {
|
||||
// If the callback has been set, then call it for each included file
|
||||
if (includeCallback) {
|
||||
for (QVector<QString>::size_type n = 0; n < includes.size(); n++) {
|
||||
auto inc = includes[n];
|
||||
int r = includeCallback(inc.first, inc.second, sectionname,
|
||||
this, includeParam);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
// By default we try to load the included file from the relative
|
||||
// directory of the current file
|
||||
|
||||
// Determine the path of the current script so that we can resolve
|
||||
// relative paths for includes
|
||||
auto path = QFileInfo(sectionname).filePath();
|
||||
|
||||
// Load the included scripts
|
||||
for (QVector<QString>::size_type n = 0; n < includes.size(); n++) {
|
||||
// If the include is a relative path, then prepend the path of
|
||||
// the originating script
|
||||
|
||||
auto inc = includes.at(n);
|
||||
if (!QFileInfo(inc.first).isAbsolute()) {
|
||||
includes[n].first = path + QDir::separator() + inc.first;
|
||||
}
|
||||
|
||||
// Include the script section
|
||||
int r = AddSectionFromFile(includes[n].first);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AsPreprocesser::LoadScriptSection(const QString &filename) {
|
||||
// Open the script file
|
||||
|
||||
QFile f(filename);
|
||||
|
||||
if (!f.open(QFile::ReadOnly)) {
|
||||
// Write a message to the engine's message callback
|
||||
auto msg = QObject::tr("Failed to open script file ") +
|
||||
QStringLiteral("'") +
|
||||
QFileInfo(filename).absoluteFilePath() + QStringLiteral("'");
|
||||
engine->WriteMessage(filename.toUtf8(), 0, 0, asMSGTYPE_ERROR,
|
||||
msg.toUtf8());
|
||||
|
||||
// TODO: Write the file where this one was included from
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Read the entire file
|
||||
auto code = f.readAll();
|
||||
f.close();
|
||||
|
||||
// Process the script section even if it is zero length so that the name is
|
||||
// registered
|
||||
return ProcessScriptSection(code, code.length(), filename, 0);
|
||||
}
|
||||
|
||||
bool AsPreprocesser::IncludeIfNotAlreadyIncluded(const QString &filename) {
|
||||
if (includedScripts.contains(filename)) {
|
||||
// Already included
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add the file to the set of included sections
|
||||
includedScripts.append(filename);
|
||||
return true;
|
||||
}
|
||||
|
||||
int AsPreprocesser::SkipStatement(const QByteArray &modifiedScript, int pos) {
|
||||
asUINT len = 0;
|
||||
|
||||
// Skip until ; or { whichever comes first
|
||||
while (pos < (int)modifiedScript.length() && modifiedScript[pos] != ';' &&
|
||||
modifiedScript[pos] != '{') {
|
||||
engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
pos += len;
|
||||
}
|
||||
|
||||
// Skip entire statement block
|
||||
if (pos < (int)modifiedScript.length() && modifiedScript[pos] == '{') {
|
||||
pos += 1;
|
||||
|
||||
// Find the end of the statement block
|
||||
int level = 1;
|
||||
while (level > 0 && pos < (int)modifiedScript.size()) {
|
||||
asETokenClass t = engine->ParseToken(
|
||||
modifiedScript.data() + pos, modifiedScript.size() - pos, &len);
|
||||
if (t == asTC_KEYWORD) {
|
||||
if (modifiedScript[pos] == '{')
|
||||
level++;
|
||||
else if (modifiedScript[pos] == '}')
|
||||
level--;
|
||||
}
|
||||
|
||||
pos += len;
|
||||
}
|
||||
} else
|
||||
pos += 1;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
int AsPreprocesser::ExcludeCode(QByteArray &modifiedScript, int pos) {
|
||||
asUINT len = 0;
|
||||
int nested = 0;
|
||||
while (pos < (int)modifiedScript.size()) {
|
||||
engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
if (modifiedScript[pos] == '#') {
|
||||
modifiedScript[pos] = ' ';
|
||||
pos++;
|
||||
|
||||
// Is it an #if or #endif directive?
|
||||
engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
QString token = modifiedScript.mid(pos, len);
|
||||
OverwriteCode(modifiedScript, pos, len);
|
||||
|
||||
if (token == "if") {
|
||||
nested++;
|
||||
} else if (token == "endif") {
|
||||
if (nested-- == 0) {
|
||||
pos += len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (modifiedScript[pos] != '\n') {
|
||||
OverwriteCode(modifiedScript, pos, len);
|
||||
}
|
||||
pos += len;
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
void AsPreprocesser::OverwriteCode(QByteArray &modifiedScript, int start,
|
||||
int len) {
|
||||
auto code = modifiedScript.data() + start;
|
||||
for (int n = 0; n < len; n++) {
|
||||
if (*code != '\n')
|
||||
*code = ' ';
|
||||
code++;
|
||||
}
|
||||
}
|
||||
|
||||
void AsPreprocesser::AddScriptSection(const QString §ion,
|
||||
const QByteArray &code, int lineOffset) {
|
||||
ScriptData data;
|
||||
data.section = section;
|
||||
data.lineOffset = lineOffset;
|
||||
data.script = code;
|
||||
modifiedScripts.append(data);
|
||||
}
|
||||
|
||||
int AsPreprocesser::ExtractMetadata(QByteArray &modifiedScript, int pos,
|
||||
QVector<QString> &metadata) {
|
||||
metadata.clear();
|
||||
|
||||
// Extract all metadata. They can be separated by whitespace and comments
|
||||
for (;;) {
|
||||
QString metadataString;
|
||||
|
||||
// Overwrite the metadata with space characters to allow compilation
|
||||
modifiedScript[pos] = ' ';
|
||||
|
||||
// Skip opening brackets
|
||||
pos += 1;
|
||||
|
||||
int level = 1;
|
||||
asUINT len = 0;
|
||||
while (level > 0 && pos < (int)modifiedScript.size()) {
|
||||
asETokenClass t = engine->ParseToken(
|
||||
modifiedScript.data() + pos, modifiedScript.size() - pos, &len);
|
||||
if (t == asTC_KEYWORD) {
|
||||
if (modifiedScript[pos] == '[')
|
||||
level++;
|
||||
else if (modifiedScript[pos] == ']')
|
||||
level--;
|
||||
}
|
||||
|
||||
// Copy the metadata to our buffer
|
||||
if (level > 0)
|
||||
metadataString.append(modifiedScript.mid(pos, len));
|
||||
|
||||
// Overwrite the metadata with space characters to allow compilation
|
||||
if (t != asTC_WHITESPACE)
|
||||
OverwriteCode(modifiedScript, pos, len);
|
||||
|
||||
pos += len;
|
||||
}
|
||||
|
||||
metadata.push_back(metadataString);
|
||||
|
||||
// Check for more metadata. Possibly separated by comments
|
||||
asETokenClass t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
while (t == asTC_COMMENT || t == asTC_WHITESPACE) {
|
||||
pos += len;
|
||||
t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
}
|
||||
|
||||
if (modifiedScript[pos] != '[')
|
||||
break;
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
int AsPreprocesser::ExtractDeclaration(QByteArray &modifiedScript, int pos,
|
||||
QString &name, QString &declaration,
|
||||
int &type) {
|
||||
declaration.clear();
|
||||
type = 0;
|
||||
|
||||
int start = pos;
|
||||
|
||||
QString token;
|
||||
asUINT len = 0;
|
||||
asETokenClass t = asTC_WHITESPACE;
|
||||
|
||||
// Skip white spaces, comments, and leading decorators
|
||||
do {
|
||||
pos += len;
|
||||
t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
token = modifiedScript.mid(pos, len);
|
||||
} while (t == asTC_WHITESPACE || t == asTC_COMMENT || token == "private" ||
|
||||
token == "protected" || token == "shared" || token == "external" ||
|
||||
token == "final" || token == "abstract");
|
||||
|
||||
// We're expecting, either a class, interface, function, or variable
|
||||
// declaration
|
||||
if (t == asTC_KEYWORD || t == asTC_IDENTIFIER) {
|
||||
token = modifiedScript.mid(pos, len);
|
||||
if (token == "interface" || token == "class" || token == "enum") {
|
||||
// Skip white spaces and comments
|
||||
do {
|
||||
pos += len;
|
||||
t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
} while (t == asTC_WHITESPACE || t == asTC_COMMENT);
|
||||
|
||||
if (t == asTC_IDENTIFIER) {
|
||||
type = MDT_TYPE;
|
||||
declaration = modifiedScript.mid(pos, len);
|
||||
pos += len;
|
||||
return pos;
|
||||
}
|
||||
} else {
|
||||
// For function declarations, store everything up to the start of
|
||||
// the statement block, except for succeeding decorators (final,
|
||||
// override, etc)
|
||||
|
||||
// For variable declaration store just the name as there can only be
|
||||
// one
|
||||
|
||||
// We'll only know if the declaration is a variable or function
|
||||
// declaration when we see the statement block, or absense of a
|
||||
// statement block.
|
||||
bool hasParenthesis = false;
|
||||
int nestedParenthesis = 0;
|
||||
declaration.append(modifiedScript.mid(pos, len));
|
||||
pos += len;
|
||||
for (; pos < (int)modifiedScript.size();) {
|
||||
t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
token = modifiedScript.mid(pos, len);
|
||||
if (t == asTC_KEYWORD) {
|
||||
if (token == "{" && nestedParenthesis == 0) {
|
||||
if (hasParenthesis) {
|
||||
// We've found the end of a function signature
|
||||
type = MDT_FUNC;
|
||||
} else {
|
||||
// We've found a virtual property. Just keep the
|
||||
// name
|
||||
declaration = name;
|
||||
type = MDT_VIRTPROP;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
if ((token == "=" && !hasParenthesis) || token == ";") {
|
||||
if (hasParenthesis) {
|
||||
// The declaration is ambigous. It can be a variable
|
||||
// with initialization, or a function prototype
|
||||
type = MDT_FUNC_OR_VAR;
|
||||
} else {
|
||||
// Substitute the declaration with just the name
|
||||
declaration = name;
|
||||
type = MDT_VAR;
|
||||
}
|
||||
return pos;
|
||||
} else if (token == "(") {
|
||||
nestedParenthesis++;
|
||||
|
||||
// This is the first parenthesis we encounter. If the
|
||||
// parenthesis isn't followed by a statement block, then
|
||||
// this is a variable declaration, in which case we
|
||||
// should only store the type and name of the variable,
|
||||
// not the initialization parameters.
|
||||
hasParenthesis = true;
|
||||
} else if (token == ")") {
|
||||
nestedParenthesis--;
|
||||
}
|
||||
} else if (t == asTC_IDENTIFIER) {
|
||||
// If a parenthesis is already found then the name is
|
||||
// already known so it must not be overwritten
|
||||
if (!hasParenthesis)
|
||||
name = token;
|
||||
}
|
||||
|
||||
// Skip trailing decorators
|
||||
if (!hasParenthesis || nestedParenthesis > 0 ||
|
||||
t != asTC_IDENTIFIER ||
|
||||
(token != "final" && token != "override" &&
|
||||
token != "delete" && token != "property"))
|
||||
declaration += token;
|
||||
|
||||
pos += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return start;
|
||||
}
|
|
@ -0,0 +1,200 @@
|
|||
/*==============================================================================
|
||||
** 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 ASPREPROCESSER_H
|
||||
#define ASPREPROCESSER_H
|
||||
|
||||
// DON'T DELETE this
|
||||
#include "AngelScript/sdk/angelscript/source/as_config.h"
|
||||
|
||||
//---------------------------
|
||||
// Declaration
|
||||
//
|
||||
|
||||
#ifndef ANGELSCRIPT_H
|
||||
// Avoid having to inform include path if header is already include before
|
||||
#include <angelscript.h>
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1200
|
||||
// disable the annoying warnings on MSVC 6
|
||||
#pragma warning(disable : 4786)
|
||||
#endif
|
||||
|
||||
#include <QMap>
|
||||
#include <QSet>
|
||||
#include <QVector>
|
||||
|
||||
class AsPreprocesser;
|
||||
class asCScriptCode;
|
||||
|
||||
// This callback will be called for each #include directive encountered by the
|
||||
// builder. The callback should call the AddSectionFromFile or
|
||||
// AddSectionFromMemory to add the included section to the script. If the
|
||||
// include cannot be resolved then the function should return a negative value
|
||||
// to abort the compilation.
|
||||
typedef int (*INCLUDECALLBACK_t)(const QString &include, bool quotedInclude,
|
||||
const QString &from, AsPreprocesser *builder,
|
||||
void *userParam);
|
||||
|
||||
// This callback will be called for each #pragma directive encountered by the
|
||||
// builder. The application can interpret the pragmaText and decide what do to
|
||||
// based on that. If the callback returns a negative value the builder will
|
||||
// report an error and abort the compilation.
|
||||
typedef int (*PRAGMACALLBACK_t)(const QByteArray &pragmaText,
|
||||
AsPreprocesser *builder, void *userParam);
|
||||
|
||||
// Helper class for loading and pre-processing script files to
|
||||
// support include directives and metadata declarations
|
||||
|
||||
class AsPreprocesser {
|
||||
public:
|
||||
explicit AsPreprocesser(asIScriptEngine *engine);
|
||||
virtual ~AsPreprocesser();
|
||||
|
||||
public:
|
||||
struct ScriptData {
|
||||
QString section;
|
||||
int lineOffset = -1;
|
||||
QByteArray script;
|
||||
};
|
||||
|
||||
public:
|
||||
// Load a script section from a file on disk
|
||||
// Returns 1 if the file was included
|
||||
// 0 if the file had already been included before
|
||||
// <0 on error
|
||||
int AddSectionFromFile(const QString &filename);
|
||||
|
||||
// Load a script section from memory
|
||||
// Returns 1 if the section was included
|
||||
// 0 if a section with the same name had already been included
|
||||
// before
|
||||
// <0 on error
|
||||
int AddSectionFromMemory(const QString §ionName, const QByteArray &code,
|
||||
int lineOffset = 0);
|
||||
|
||||
QList<ScriptData> GetScriptData() const;
|
||||
|
||||
// Returns the engine
|
||||
asIScriptEngine *GetEngine();
|
||||
|
||||
// Register the callback for resolving include directive
|
||||
void SetIncludeCallback(INCLUDECALLBACK_t callback, void *userParam);
|
||||
|
||||
// Register the callback for resolving pragma directive
|
||||
void SetPragmaCallback(PRAGMACALLBACK_t callback, void *userParam);
|
||||
|
||||
// Add a pre-processor define for conditional compilation
|
||||
void DefineWord(const QString &word);
|
||||
|
||||
// Enumerate included script sections
|
||||
unsigned int GetSectionCount() const;
|
||||
|
||||
QString GetSectionName(unsigned int idx) const;
|
||||
|
||||
// Get metadata declared for classes, interfaces, and enums
|
||||
QVector<QString> GetMetadataForType(int typeId);
|
||||
|
||||
// Get metadata declared for functions
|
||||
QVector<QString> GetMetadataForFunc(asIScriptFunction *func);
|
||||
|
||||
// Get metadata declared for global variables
|
||||
QVector<QString> GetMetadataForVar(int varIdx);
|
||||
|
||||
// Get metadata declared for class variables
|
||||
QVector<QString> GetMetadataForTypeProperty(int typeId, int varIdx);
|
||||
|
||||
// Get metadata declared for class methods
|
||||
QVector<QString> GetMetadataForTypeMethod(int typeId,
|
||||
asIScriptFunction *method);
|
||||
|
||||
protected:
|
||||
void ClearAll();
|
||||
int ProcessScriptSection(const QByteArray &script, int length,
|
||||
const QString §ionname, int lineOffset);
|
||||
int LoadScriptSection(const QString &filename);
|
||||
bool IncludeIfNotAlreadyIncluded(const QString &filename);
|
||||
|
||||
int SkipStatement(const QByteArray &modifiedScript, int pos);
|
||||
|
||||
int ExcludeCode(QByteArray &modifiedScript, int pos);
|
||||
void OverwriteCode(QByteArray &modifiedScript, int start, int len);
|
||||
|
||||
void AddScriptSection(const QString §ion, const QByteArray &code,
|
||||
int lineOffset);
|
||||
|
||||
asIScriptEngine *engine;
|
||||
QList<ScriptData> modifiedScripts;
|
||||
|
||||
INCLUDECALLBACK_t includeCallback;
|
||||
void *includeParam;
|
||||
|
||||
PRAGMACALLBACK_t pragmaCallback;
|
||||
void *pragmaParam;
|
||||
|
||||
int ExtractMetadata(QByteArray &modifiedScript, int pos,
|
||||
QVector<QString> &metadata);
|
||||
int ExtractDeclaration(QByteArray &modifiedScript, int pos, QString &name,
|
||||
QString &declaration, int &type);
|
||||
|
||||
enum METADATATYPE {
|
||||
MDT_TYPE = 1,
|
||||
MDT_FUNC = 2,
|
||||
MDT_VAR = 3,
|
||||
MDT_VIRTPROP = 4,
|
||||
MDT_FUNC_OR_VAR = 5
|
||||
};
|
||||
|
||||
// Temporary structure for storing metadata and declaration
|
||||
struct SMetadataDecl {
|
||||
SMetadataDecl(const QVector<QString> &m, const QString &n,
|
||||
const QString &d, int t, const QString &c,
|
||||
const QString &ns)
|
||||
: metadata(m), name(n), declaration(d), type(t), parentClass(c),
|
||||
nameSpace(ns) {}
|
||||
QVector<QString> metadata;
|
||||
QString name;
|
||||
QString declaration;
|
||||
int type;
|
||||
QString parentClass;
|
||||
QString nameSpace;
|
||||
};
|
||||
QVector<SMetadataDecl> foundDeclarations;
|
||||
QString currentClass;
|
||||
QString currentNamespace;
|
||||
|
||||
// Storage of metadata for global declarations
|
||||
QMap<int, QVector<QString>> typeMetadataMap;
|
||||
QMap<int, QVector<QString>> funcMetadataMap;
|
||||
QMap<int, QVector<QString>> varMetadataMap;
|
||||
|
||||
// Storage of metadata for class member declarations
|
||||
struct SClassMetadata {
|
||||
SClassMetadata(const QString &aName) : className(aName) {}
|
||||
QString className;
|
||||
QMap<int, QVector<QString>> funcMetadataMap;
|
||||
QMap<int, QVector<QString>> varMetadataMap;
|
||||
};
|
||||
QMap<int, SClassMetadata> classMetadataMap;
|
||||
|
||||
QVector<QString> includedScripts;
|
||||
|
||||
QVector<QString> definedWords;
|
||||
};
|
||||
|
||||
#endif // ASPREPROCESSER_H
|
|
@ -8,6 +8,10 @@
|
|||
Q_GLOBAL_STATIC_WITH_ARGS(QString, CLANG_ENABLE_FMT, ("clang.enabled"))
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QString, CLANG_AUTO_FMT, ("clang.auto"))
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QString, CLANG_STYLE, ("clang.style"))
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QString, CLANG_CUSTOM_STYLE, ("clang.customStyle"))
|
||||
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QString, CLANG_DEFAULT_CUSTOM,
|
||||
("BasedOnStyle: llvm, IndentWidth: 4"))
|
||||
|
||||
ClangFormatManager::ClangFormatManager() {
|
||||
// load config
|
||||
|
@ -19,6 +23,19 @@ ClangFormatManager::ClangFormatManager() {
|
|||
auto styles = supportedStyles();
|
||||
READ_CONFIG_STRING(m_clangStyle, CLANG_STYLE, styles.first());
|
||||
|
||||
QByteArray buffer;
|
||||
buffer = READ_CONFIG(CLANG_CUSTOM_STYLE, QByteArray()).toByteArray();
|
||||
if (buffer.isEmpty()) {
|
||||
m_customStyleString = *CLANG_DEFAULT_CUSTOM;
|
||||
} else {
|
||||
auto data = qUncompress(buffer);
|
||||
if (buffer.isEmpty()) {
|
||||
m_customStyleString = QString::fromUtf8(data);
|
||||
} else {
|
||||
m_customStyleString = *CLANG_DEFAULT_CUSTOM;
|
||||
}
|
||||
}
|
||||
|
||||
// ok find
|
||||
refind();
|
||||
}
|
||||
|
@ -56,6 +73,11 @@ bool ClangFormatManager::refind() {
|
|||
auto vstr = QStringLiteral("clang-format version ");
|
||||
if (ret.startsWith(vstr)) {
|
||||
m_clangVersion = ret.mid(vstr.length()).simplified();
|
||||
|
||||
if (!checkClangCustomStyle(m_customStyleString)) {
|
||||
m_customStyleString = *CLANG_DEFAULT_CUSTOM;
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
m_clangPath.clear();
|
||||
|
@ -137,16 +159,57 @@ QString ClangFormatManager::runClangFormat(const QStringList ¶ms,
|
|||
}
|
||||
}
|
||||
|
||||
bool ClangFormatManager::autoFormat() const { return m_autoFmt; }
|
||||
|
||||
void ClangFormatManager::setAutoFormat(bool newAutoFmt) {
|
||||
m_autoFmt = newAutoFmt;
|
||||
}
|
||||
|
||||
bool ClangFormatManager::checkClangCustomStyle(const QString &styles) {
|
||||
bool ok = false;
|
||||
auto style = QStringLiteral("--style={%1}").arg(styles.simplified());
|
||||
runClangFormat({style, QStringLiteral("--assume-filename=wing.cpp")},
|
||||
QStringLiteral("void main(){}"), ok);
|
||||
return ok;
|
||||
}
|
||||
quint32 ClangFormatManager::identWidth() const { return m_identWidth; }
|
||||
|
||||
void ClangFormatManager::setIdentWidth(quint32 newIdentWidth) {
|
||||
m_identWidth = newIdentWidth;
|
||||
}
|
||||
|
||||
void ClangFormatManager::save() {
|
||||
HANDLE_CONFIG;
|
||||
WRITE_CONFIG(CLANG_ENABLE_FMT, m_enabled);
|
||||
WRITE_CONFIG(CLANG_AUTO_FMT, m_autoFmt);
|
||||
WRITE_CONFIG(CLANG_STYLE, m_clangStyle);
|
||||
WRITE_CONFIG(CLANG_CUSTOM_STYLE, qCompress(m_customStyleString.toUtf8()));
|
||||
}
|
||||
|
||||
void ClangFormatManager::reset() {
|
||||
m_enabled = true;
|
||||
m_autoFmt = false;
|
||||
auto styles = supportedStyles();
|
||||
m_clangPath = styles.first();
|
||||
m_customStyleString = *CLANG_DEFAULT_CUSTOM;
|
||||
save();
|
||||
}
|
||||
|
||||
QString ClangFormatManager::clangStyle() const { return m_clangStyle; }
|
||||
|
||||
void ClangFormatManager::setClangStyle(const QString &newClangStyle) {
|
||||
m_clangStyle = newClangStyle;
|
||||
bool ClangFormatManager::setClangStyle(const QString &newClangStyle) {
|
||||
if (m_clangStyle != newClangStyle) {
|
||||
if (checkClangCustomStyle(newClangStyle)) {
|
||||
m_clangStyle = newClangStyle;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int ClangFormatManager::clangCurrentStyleIndex() const {
|
||||
return supportedStyles().indexOf(m_clangStyle);
|
||||
}
|
||||
|
||||
bool ClangFormatManager::enabled() const { return m_enabled; }
|
||||
|
|
|
@ -25,7 +25,6 @@ public:
|
|||
QString version() const;
|
||||
|
||||
QString customStyleString() const;
|
||||
|
||||
void setCustomStyleString(const QString &newCustomStyleString);
|
||||
|
||||
QString path() const;
|
||||
|
@ -34,14 +33,24 @@ public:
|
|||
void setEnabled(bool newEnabled);
|
||||
|
||||
QString clangStyle() const;
|
||||
void setClangStyle(const QString &newClangStyle);
|
||||
bool setClangStyle(const QString &newClangStyle);
|
||||
int clangCurrentStyleIndex() const;
|
||||
|
||||
quint32 identWidth() const;
|
||||
void setIdentWidth(quint32 newIdentWidth);
|
||||
|
||||
public:
|
||||
void save();
|
||||
void reset();
|
||||
|
||||
bool autoFormat() const;
|
||||
void setAutoFormat(bool newAutoFmt);
|
||||
|
||||
private:
|
||||
explicit ClangFormatManager();
|
||||
|
||||
bool checkClangCustomStyle(const QString &styles);
|
||||
|
||||
QString runClangFormat(const QStringList ¶ms, const QString &stdinput,
|
||||
bool &ok);
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "qformat.h"
|
||||
#include "qformatscheme.h"
|
||||
#include "qsnippetmanager.h"
|
||||
#include "utilities.h"
|
||||
|
||||
LangService &LangService::instance() {
|
||||
static LangService ins;
|
||||
|
@ -27,16 +28,9 @@ void LangService::init(asIScriptEngine *engine) {
|
|||
break;
|
||||
}
|
||||
|
||||
// additional formats
|
||||
QFormat fmt;
|
||||
fmt.foreground = Qt::red;
|
||||
format->setFormat(QStringLiteral("stderr"), fmt);
|
||||
fmt.foreground = QColorConstants::Svg::gold;
|
||||
format->setFormat(QStringLiteral("stdwarn"), fmt);
|
||||
fmt.foreground = Qt::cyan;
|
||||
format->setFormat(QStringLiteral("stdout"), fmt);
|
||||
|
||||
addAdditionalFormat(format);
|
||||
QDocument::setDefaultFormatScheme(format);
|
||||
_formatSchemes.insert(defaultSchemeName(), format);
|
||||
|
||||
m_language = new QLanguageFactory(format, this);
|
||||
m_language->addDefinitionPath(QStringLiteral(":/qcodeedit"));
|
||||
|
@ -44,17 +38,80 @@ void LangService::init(asIScriptEngine *engine) {
|
|||
m_language->addCompletionEngine(_completion);
|
||||
|
||||
m_snippetManager = new QSnippetManager(this);
|
||||
QDir snippetDir(Utilities::getAppDataPath());
|
||||
const auto snippetName = QStringLiteral("snippets");
|
||||
if (!snippetDir.exists(snippetName)) {
|
||||
snippetDir.mkdir(snippetName);
|
||||
}
|
||||
if (snippetDir.cd(snippetName)) {
|
||||
m_snippetManager->loadSnippetsFromDirectory(snippetDir.absolutePath());
|
||||
}
|
||||
|
||||
m_snipbind = new QSnippetBinding(m_snippetManager);
|
||||
|
||||
initAdditionalFormatScheme();
|
||||
}
|
||||
|
||||
LangService::LangService() : QObject(nullptr) {}
|
||||
|
||||
LangService::~LangService() { delete m_snipbind; }
|
||||
LangService::~LangService() {
|
||||
delete m_snipbind;
|
||||
m_snipbind = nullptr;
|
||||
qDeleteAll(_formatSchemes);
|
||||
}
|
||||
|
||||
void LangService::initAdditionalFormatScheme() {
|
||||
QDir appDataDir(Utilities::getAppDataPath());
|
||||
const auto dirName = QStringLiteral("scheme");
|
||||
appDataDir.mkdir(dirName);
|
||||
if (appDataDir.exists(dirName)) {
|
||||
appDataDir.cd(dirName);
|
||||
for (auto &sch :
|
||||
appDataDir.entryInfoList({QStringLiteral("*.qxf")}, QDir::Files)) {
|
||||
auto fmt = new QFormatScheme(sch.absoluteFilePath());
|
||||
if (fmt->formatCount()) {
|
||||
addAdditionalFormat(fmt);
|
||||
_formatSchemes.insert(sch.baseName(), fmt);
|
||||
} else {
|
||||
delete fmt;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QHash<QString, QFormatScheme *> LangService::formatSchemes() const {
|
||||
return _formatSchemes;
|
||||
}
|
||||
|
||||
const QString LangService::defaultSchemeName() const { return tr("Default"); }
|
||||
|
||||
void LangService::saveSnippets() {
|
||||
QDir snippetDir(Utilities::getAppDataPath());
|
||||
const auto snippetName = QStringLiteral("snippets");
|
||||
if (!snippetDir.exists(snippetName)) {
|
||||
snippetDir.mkdir(snippetName);
|
||||
}
|
||||
if (snippetDir.cd(snippetName)) {
|
||||
m_snippetManager->saveSnippetsToDirectory(snippetDir.absolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
QSnippetManager *LangService::snippetManager() const {
|
||||
return m_snippetManager;
|
||||
}
|
||||
|
||||
void LangService::addAdditionalFormat(QFormatScheme *scheme) {
|
||||
if (scheme) {
|
||||
QFormat fmt;
|
||||
fmt.foreground = Qt::red;
|
||||
scheme->setFormat(QStringLiteral("stderr"), fmt);
|
||||
fmt.foreground = QColorConstants::Svg::gold;
|
||||
scheme->setFormat(QStringLiteral("stdwarn"), fmt);
|
||||
fmt.foreground = Qt::green;
|
||||
scheme->setFormat(QStringLiteral("stdout"), fmt);
|
||||
}
|
||||
}
|
||||
|
||||
QLanguageFactory *LangService::languageFactory() const { return m_language; }
|
||||
|
||||
void LangService::applyLanguageSerivce(QEditor *editor) {
|
||||
|
|
|
@ -25,10 +25,21 @@ public:
|
|||
|
||||
QSnippetManager *snippetManager() const;
|
||||
|
||||
static void addAdditionalFormat(QFormatScheme *scheme);
|
||||
|
||||
QHash<QString, QFormatScheme *> formatSchemes() const;
|
||||
|
||||
const QString defaultSchemeName() const;
|
||||
|
||||
void saveSnippets();
|
||||
|
||||
private:
|
||||
LangService();
|
||||
~LangService();
|
||||
|
||||
private:
|
||||
void initAdditionalFormatScheme();
|
||||
|
||||
private:
|
||||
QSnippetBinding *m_snipbind = nullptr;
|
||||
QLanguageFactory *m_language = nullptr;
|
||||
|
@ -36,6 +47,8 @@ private:
|
|||
|
||||
AsCompletion *_completion = nullptr;
|
||||
|
||||
QHash<QString, QFormatScheme *> _formatSchemes;
|
||||
|
||||
Q_DISABLE_COPY_MOVE(LangService)
|
||||
};
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "languagemanager.h"
|
||||
|
||||
#include "class/settingmanager.h"
|
||||
#include "wingmessagebox.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
@ -36,6 +37,8 @@ LanguageManager &LanguageManager::instance() {
|
|||
}
|
||||
|
||||
LanguageManager::LanguageManager() {
|
||||
m_langMap = {{"zh_CN", QStringLiteral("简体中文")}};
|
||||
|
||||
auto langPath =
|
||||
qApp->applicationDirPath() + QDir::separator() + QStringLiteral("lang");
|
||||
|
||||
|
@ -46,34 +49,27 @@ LanguageManager::LanguageManager() {
|
|||
for (auto &langinfo : langFiles) {
|
||||
auto lang = langinfo.fileName();
|
||||
QLocale locale(lang);
|
||||
if (locale == QLocale::C) {
|
||||
if (locale == QLocale::c()) {
|
||||
continue;
|
||||
}
|
||||
m_langs << lang;
|
||||
m_localeMap.insert(lang, locale);
|
||||
}
|
||||
|
||||
_defaultLocale = QLocale::system();
|
||||
auto lang = SettingManager::instance().defaultLang();
|
||||
if (lang.isEmpty()) {
|
||||
_defaultLocale = QLocale::system();
|
||||
} else {
|
||||
QLocale locale(lang);
|
||||
if (locale == QLocale::c()) {
|
||||
_defaultLocale = QLocale::system();
|
||||
} else {
|
||||
_defaultLocale = locale;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_langs.isEmpty()) {
|
||||
#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
|
||||
if (QLocale::China == _defaultLocale.territory()
|
||||
#else
|
||||
if (QLocale::China == _defaultLocale.country()
|
||||
#endif
|
||||
) {
|
||||
QMessageBox::critical(
|
||||
nullptr, QStringLiteral("程序损坏"),
|
||||
QStringLiteral(
|
||||
"语言文件已损坏,请尝试重装软件以解决这个问题。"));
|
||||
} else {
|
||||
QMessageBox::critical(
|
||||
nullptr, QStringLiteral("Corruption"),
|
||||
QStringLiteral("The language file has been damaged. "
|
||||
"Please try reinstalling the software to "
|
||||
"solve the problem."));
|
||||
}
|
||||
qApp->exit(-1);
|
||||
abortAndExit();
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
|
@ -123,13 +119,9 @@ LanguageManager::LanguageManager() {
|
|||
qApp->installTranslator(translator);
|
||||
}
|
||||
} else {
|
||||
WingMessageBox::critical(
|
||||
nullptr, qAppName(),
|
||||
"Translation files loading error! Please try to reinstall.");
|
||||
abortAndExit();
|
||||
}
|
||||
|
||||
m_langMap = {{"zh_CN", tr("Chinese(Simplified)")}};
|
||||
|
||||
for (auto &lang : m_langs) {
|
||||
m_langsDisplay << m_langMap.value(lang, lang);
|
||||
}
|
||||
|
@ -141,22 +133,24 @@ bool LanguageManager::unpackTr(const QString &filename) {
|
|||
}
|
||||
|
||||
QZipReader reader(filename);
|
||||
|
||||
if (reader.count() != 5) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_data = {};
|
||||
for (auto &file : reader.fileInfoList()) {
|
||||
if (file.isValid() && file.isFile) {
|
||||
if (file.filePath.endsWith(QStringLiteral("winghex.qm"))) {
|
||||
if (file.filePath == QStringLiteral("winghex.qm")) {
|
||||
_data.trFiles = reader.fileData(file.filePath);
|
||||
} else if (file.filePath.endsWith(QStringLiteral("about.md"))) {
|
||||
} else if (file.filePath == QStringLiteral("about.md")) {
|
||||
_data.about = reader.fileData(file.filePath);
|
||||
} else if (file.filePath.endsWith(
|
||||
QStringLiteral("components.md"))) {
|
||||
} else if (file.filePath == QStringLiteral("components.md")) {
|
||||
_data.component = reader.fileData(file.filePath);
|
||||
} else if (file.filePath.endsWith(QStringLiteral("credits.md"))) {
|
||||
} else if (file.filePath == QStringLiteral("credits.md")) {
|
||||
_data.credit = reader.fileData(file.filePath);
|
||||
} else if (file.filePath.endsWith(QStringLiteral("devs.md"))) {
|
||||
} else if (file.filePath == QStringLiteral("devs.md")) {
|
||||
_data.dev = reader.fileData(file.filePath);
|
||||
} else if (file.filePath.endsWith(QStringLiteral("trans.md"))) {
|
||||
_data.trans = reader.fileData(file.filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -164,7 +158,27 @@ bool LanguageManager::unpackTr(const QString &filename) {
|
|||
|
||||
return !_data.trFiles.isEmpty() && !_data.about.isEmpty() &&
|
||||
!_data.component.isEmpty() && !_data.credit.isEmpty() &&
|
||||
!_data.dev.isEmpty() && !_data.trans.isEmpty();
|
||||
!_data.dev.isEmpty();
|
||||
}
|
||||
|
||||
void LanguageManager::abortAndExit() {
|
||||
#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
|
||||
if (QLocale::China == _defaultLocale.territory()
|
||||
#else
|
||||
if (QLocale::China == _defaultLocale.country()
|
||||
#endif
|
||||
) {
|
||||
WingMessageBox::critical(
|
||||
nullptr, QStringLiteral("程序损坏"),
|
||||
QStringLiteral("语言文件已损坏,请尝试重装软件以解决这个问题。"));
|
||||
} else {
|
||||
WingMessageBox::critical(
|
||||
nullptr, QStringLiteral("Corruption"),
|
||||
QStringLiteral("The language file has been damaged. "
|
||||
"Please try reinstalling the software to "
|
||||
"solve the problem."));
|
||||
}
|
||||
qApp->exit(-1);
|
||||
}
|
||||
|
||||
QLocale LanguageManager::defaultLocale() const { return _defaultLocale; }
|
||||
|
|
|
@ -33,7 +33,6 @@ public:
|
|||
QString component;
|
||||
QString dev;
|
||||
QString credit;
|
||||
QString trans;
|
||||
};
|
||||
|
||||
public:
|
||||
|
@ -53,6 +52,8 @@ private:
|
|||
private:
|
||||
bool unpackTr(const QString &filename);
|
||||
|
||||
void abortAndExit();
|
||||
|
||||
private:
|
||||
LanguageData _data;
|
||||
|
||||
|
|
|
@ -31,15 +31,20 @@
|
|||
* If you want to make it more powerful, PR will be welcomed.
|
||||
*/
|
||||
|
||||
QAsParser::QAsParser(asIScriptEngine *engine) : asBuilder(), _engine(engine) {
|
||||
QAsParser::QAsParser(asIScriptEngine *engine)
|
||||
: asBuilder(engine), _engine(engine) {
|
||||
addGlobalFunctionCompletion(engine);
|
||||
addClassCompletion(engine);
|
||||
addEnumCompletion(engine);
|
||||
_buffer.clear();
|
||||
_buffer.squeeze();
|
||||
}
|
||||
|
||||
QAsParser::~QAsParser() {
|
||||
qDeleteAll(_headerNodes);
|
||||
_headerNodes.clear();
|
||||
qDeleteAll(_nodes);
|
||||
_nodes.clear();
|
||||
}
|
||||
|
||||
QByteArray QAsParser::getFnParamDeclString(asIScriptFunction *fn,
|
||||
|
@ -164,7 +169,7 @@ QByteArray QAsParser::getFnRetTypeString(asIScriptFunction *fn,
|
|||
}
|
||||
|
||||
bool QAsParser::parse(const QString &filename) {
|
||||
if (StartNewModule(_engine, "as_parser") != 0) {
|
||||
if (StartNewModule("as_parser") != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -179,14 +184,14 @@ bool QAsParser::parse(const QString &filename) {
|
|||
Q_ASSERT(mod);
|
||||
asCParser parser(mod->m_builder);
|
||||
|
||||
m_code.reset(new asCScriptCode);
|
||||
m_code->SetCode("as_parser", modifiedScript.data(), true);
|
||||
// m_code.reset(new asCScriptCode);
|
||||
// m_code->SetCode("as_parser", modifiedScript.data(), true);
|
||||
|
||||
parser.ParseScript(m_code.get());
|
||||
// parser.ParseScript(m_code.get());
|
||||
|
||||
auto pnodes = parser.GetScriptNode();
|
||||
// auto pnodes = parser.GetScriptNode();
|
||||
|
||||
QList<QCodeNode *> qnodes;
|
||||
// QList<QCodeNode *> qnodes;
|
||||
|
||||
// do {
|
||||
// auto node = asNode2CodeNode(pnodes);
|
||||
|
@ -233,7 +238,7 @@ void QAsParser::addGlobalFunctionCompletion(asIScriptEngine *engine) {
|
|||
_maps[ns] << fnInfo;
|
||||
}
|
||||
|
||||
auto node = new QCodeNode;
|
||||
auto node = getNewHeadNodePointer(QByteArray());
|
||||
node->setNodeType(QCodeNode::Group);
|
||||
for (auto p = _maps.keyBegin(); p != _maps.keyEnd(); p++) {
|
||||
if (p->isEmpty()) {
|
||||
|
@ -242,28 +247,20 @@ void QAsParser::addGlobalFunctionCompletion(asIScriptEngine *engine) {
|
|||
auto nsnode = new QCodeNode;
|
||||
nsnode->setNodeType(QCodeNode::Namespace);
|
||||
nsnode->setRole(QCodeNode::Name, *p);
|
||||
nsnode->setParent(node);
|
||||
node->children().append(nsnode);
|
||||
nsnode->attach(node);
|
||||
}
|
||||
_headerNodes << node;
|
||||
|
||||
for (auto p = _maps.keyValueBegin(); p != _maps.keyValueEnd(); p++) {
|
||||
auto node = new QCodeNode;
|
||||
_headerNodes << node;
|
||||
auto node = getNewHeadNodePointer(p->first);
|
||||
if (p->first.isEmpty()) {
|
||||
node->setNodeType(QCodeNode::Group);
|
||||
} else {
|
||||
node->setNodeType(QCodeNode::Namespace);
|
||||
}
|
||||
node->setRole(QCodeNode::Name, p->first);
|
||||
|
||||
auto pnodes = &node->children();
|
||||
auto nodeParent = node;
|
||||
|
||||
for (auto &fn : p->second) {
|
||||
auto node = newFnCodeNode(fn);
|
||||
node->setParent(nodeParent);
|
||||
pnodes->append(node);
|
||||
auto fnnode = newFnCodeNode(fn);
|
||||
fnnode->attach(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -293,26 +290,16 @@ void QAsParser::addEnumCompletion(asIScriptEngine *engine) {
|
|||
}
|
||||
|
||||
for (auto p = _maps.keyValueBegin(); p != _maps.keyValueEnd(); p++) {
|
||||
auto node = new QCodeNode;
|
||||
_headerNodes << node;
|
||||
auto node = getNewHeadNodePointer(p->first);
|
||||
if (p->first.isEmpty()) {
|
||||
node->setNodeType(QCodeNode::Group);
|
||||
} else {
|
||||
node->setNodeType(QCodeNode::Namespace);
|
||||
}
|
||||
node->setRole(QCodeNode::Name, p->first);
|
||||
|
||||
auto pnodes = &node->children();
|
||||
auto nodeParent = node;
|
||||
for (auto &e : p->second) {
|
||||
auto node = new QCodeNode;
|
||||
node->setNodeType(QCodeNode::Enum);
|
||||
node->setRole(QCodeNode::Name, e.name);
|
||||
node->setParent(nodeParent);
|
||||
pnodes->append(node);
|
||||
|
||||
auto enode = newEnumCodeNode(e);
|
||||
_headerNodes << enode;
|
||||
enode->attach(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -385,32 +372,22 @@ void QAsParser::addClassCompletion(asIScriptEngine *engine) {
|
|||
}
|
||||
|
||||
for (auto p = _maps.keyValueBegin(); p != _maps.keyValueEnd(); p++) {
|
||||
auto node = new QCodeNode;
|
||||
_headerNodes << node;
|
||||
auto node = getNewHeadNodePointer(p->first);
|
||||
if (p->first.isEmpty()) {
|
||||
node->setNodeType(QCodeNode::Group);
|
||||
} else {
|
||||
node->setNodeType(QCodeNode::Namespace);
|
||||
}
|
||||
node->setRole(QCodeNode::Name, p->first);
|
||||
|
||||
auto pnodes = &node->children();
|
||||
auto nodeParent = node;
|
||||
for (auto &cls : p->second) {
|
||||
auto node = new QCodeNode;
|
||||
node->setNodeType(QCodeNode::Class);
|
||||
node->setRole(QCodeNode::Name, cls.name);
|
||||
node->setParent(nodeParent);
|
||||
pnodes->append(node);
|
||||
|
||||
auto clsnode = new QCodeNode;
|
||||
_clsNodes << clsnode;
|
||||
clsnode->setNodeType(QCodeNode::Class);
|
||||
clsnode->setRole(QCodeNode::Name, cls.name);
|
||||
clsnode->attach(node);
|
||||
|
||||
for (auto &m : cls.methods) {
|
||||
auto node = newFnCodeNode(m);
|
||||
node->setParent(clsnode);
|
||||
clsnode->children().append(node);
|
||||
node->attach(clsnode);
|
||||
}
|
||||
|
||||
for (auto &p : cls.properties) {
|
||||
|
@ -436,6 +413,18 @@ void QAsParser::addClassCompletion(asIScriptEngine *engine) {
|
|||
}
|
||||
}
|
||||
|
||||
QCodeNode *QAsParser::getNewHeadNodePointer(const QByteArray &name) {
|
||||
auto ptr = _buffer.value(name, nullptr);
|
||||
if (ptr) {
|
||||
return ptr;
|
||||
}
|
||||
auto node = new QCodeNode;
|
||||
node->setRole(QCodeNode::Name, name);
|
||||
_headerNodes.append(node);
|
||||
_buffer.insert(name, node);
|
||||
return node;
|
||||
}
|
||||
|
||||
QCodeNode *QAsParser::newFnCodeNode(const FnInfo &info) {
|
||||
auto node = new QCodeNode;
|
||||
node->setNodeType(QCodeNode::Function);
|
||||
|
@ -468,6 +457,4 @@ QCodeNode *QAsParser::newEnumCodeNode(const EnumInfo &info) {
|
|||
return enode;
|
||||
}
|
||||
|
||||
QList<QCodeNode *> QAsParser::classNodes() const { return _clsNodes; }
|
||||
|
||||
QList<QCodeNode *> QAsParser::codeNodes() const { return _nodes; }
|
||||
|
|
|
@ -75,13 +75,13 @@ public:
|
|||
|
||||
const QList<QCodeNode *> &headerNodes() const;
|
||||
|
||||
QList<QCodeNode *> classNodes() const;
|
||||
|
||||
private:
|
||||
void addGlobalFunctionCompletion(asIScriptEngine *engine);
|
||||
void addEnumCompletion(asIScriptEngine *engine);
|
||||
void addClassCompletion(asIScriptEngine *engine);
|
||||
|
||||
QCodeNode *getNewHeadNodePointer(const QByteArray &name);
|
||||
|
||||
private:
|
||||
QCodeNode *newFnCodeNode(const FnInfo &info);
|
||||
|
||||
|
@ -90,9 +90,10 @@ private:
|
|||
private:
|
||||
asIScriptEngine *_engine;
|
||||
QScopedPointer<asCScriptCode> m_code;
|
||||
QList<QCodeNode *> _headerNodes;
|
||||
QList<QCodeNode *> _clsNodes;
|
||||
QList<QCodeNode *> _nodes;
|
||||
|
||||
QHash<QString, QCodeNode *> _buffer;
|
||||
QList<QCodeNode *> _headerNodes;
|
||||
};
|
||||
|
||||
#endif // !_QCPP_PARSER_H_
|
||||
|
|
|
@ -94,9 +94,7 @@ QCodeNode::QCodeNode() : line(-1), _parent(nullptr) {}
|
|||
|
||||
QCodeNode::~QCodeNode() {
|
||||
QCodeNode::detach();
|
||||
|
||||
_parent = nullptr;
|
||||
|
||||
clear();
|
||||
}
|
||||
|
||||
|
@ -106,10 +104,8 @@ void QCodeNode::attach(QCodeNode *p) {
|
|||
if (!p || p->_children.contains(this))
|
||||
return;
|
||||
|
||||
int row = p->_children.length();
|
||||
|
||||
_parent = p;
|
||||
p->_children.insert(row, this);
|
||||
p->_children.append(this);
|
||||
}
|
||||
|
||||
void QCodeNode::detach() {
|
||||
|
@ -134,21 +130,15 @@ int QCodeNode::getLine() const { return line; }
|
|||
void QCodeNode::setLine(int newLine) { line = newLine; }
|
||||
|
||||
void QCodeNode::clear() {
|
||||
QList<QCodeNode *> c = _children;
|
||||
|
||||
removeAll();
|
||||
|
||||
qDeleteAll(c);
|
||||
}
|
||||
|
||||
void QCodeNode::removeAll() {
|
||||
if (_children.isEmpty())
|
||||
return;
|
||||
|
||||
for (auto &n : _children) {
|
||||
n->_parent = nullptr;
|
||||
n->clear();
|
||||
}
|
||||
|
||||
qDeleteAll(_children);
|
||||
_children.clear();
|
||||
}
|
||||
|
||||
|
@ -176,7 +166,7 @@ QByteArray QCodeNode::context() const {
|
|||
return p ? p->role(Context) : role(Context);
|
||||
}
|
||||
|
||||
QByteArray QCodeNode::qualifiedName(bool ext) const {
|
||||
QByteArray QCodeNode::qualifiedBaseName(bool ext) const {
|
||||
int t = type();
|
||||
|
||||
if (t == Group)
|
||||
|
@ -186,11 +176,21 @@ QByteArray QCodeNode::qualifiedName(bool ext) const {
|
|||
if (ext) {
|
||||
if (_parent && _parent->type() == Namespace) {
|
||||
cxt += _parent->role(Name);
|
||||
cxt += "::";
|
||||
}
|
||||
cxt += "::";
|
||||
}
|
||||
|
||||
cxt += role(Name);
|
||||
return cxt;
|
||||
}
|
||||
|
||||
QByteArray QCodeNode::qualifiedName(bool ext) const {
|
||||
int t = type();
|
||||
|
||||
if (t == Group)
|
||||
return QByteArray();
|
||||
|
||||
auto cxt = qualifiedBaseName(ext);
|
||||
|
||||
if (t == Function) {
|
||||
cxt += "(";
|
||||
|
@ -407,6 +407,8 @@ QByteArray QCodeNode::role(RoleIndex r) const { return roles.value(r); }
|
|||
|
||||
void QCodeNode::setRole(RoleIndex r, const QByteArray &b) { roles[r] = b; }
|
||||
|
||||
QList<QCodeNode *> &QCodeNode::children() { return _children; }
|
||||
|
||||
void QCodeNode::setNodeType(DefaultNodeTypes t) {
|
||||
setRole(NodeType, QByteArray(1, t));
|
||||
}
|
||||
|
|
|
@ -112,6 +112,7 @@ public:
|
|||
|
||||
int type() const;
|
||||
QByteArray context() const;
|
||||
QByteArray qualifiedBaseName(bool ext = false) const;
|
||||
QByteArray qualifiedName(bool ext = false) const;
|
||||
|
||||
QVariant data(int role) const;
|
||||
|
@ -119,12 +120,11 @@ public:
|
|||
QByteArray role(RoleIndex r) const;
|
||||
void setRole(RoleIndex r, const QByteArray &b);
|
||||
|
||||
QList<QCodeNode *> &children() { return _children; }
|
||||
QList<QCodeNode *> &children();
|
||||
|
||||
void setNodeType(DefaultNodeTypes t);
|
||||
|
||||
void clear();
|
||||
void removeAll();
|
||||
|
||||
void attach(QCodeNode *p);
|
||||
void detach();
|
||||
|
|
|
@ -17,18 +17,15 @@
|
|||
|
||||
#include "scriptmachine.h"
|
||||
|
||||
#include "AngelScript/sdk/add_on/datetime/datetime.h"
|
||||
#include "AngelScript/sdk/add_on/scriptany/scriptany.h"
|
||||
#include "AngelScript/sdk/add_on/scriptarray/scriptarray.h"
|
||||
#include "AngelScript/sdk/add_on/scriptdictionary/scriptdictionary.h"
|
||||
#include "AngelScript/sdk/add_on/scriptfile/scriptfilesystem.h"
|
||||
#include "AngelScript/sdk/add_on/scriptgrid/scriptgrid.h"
|
||||
#include "AngelScript/sdk/add_on/scripthandle/scripthandle.h"
|
||||
#include "AngelScript/sdk/add_on/scripthelper/scripthelper.h"
|
||||
#include "AngelScript/sdk/add_on/scriptmath/scriptmath.h"
|
||||
#include "AngelScript/sdk/add_on/scriptmath/scriptmathcomplex.h"
|
||||
#include "AngelScript/sdk/add_on/weakref/weakref.h"
|
||||
#include "class/qasparser.h"
|
||||
#include "plugin/pluginsystem.h"
|
||||
#include "scriptaddon/scriptcolor.h"
|
||||
#include "scriptaddon/scriptqstring.h"
|
||||
|
@ -83,8 +80,6 @@ bool ScriptMachine::configureEngine(asIScriptEngine *engine) {
|
|||
RegisterScriptAny(engine);
|
||||
RegisterScriptDictionary(engine);
|
||||
RegisterScriptGrid(engine);
|
||||
RegisterScriptDateTime(engine);
|
||||
RegisterScriptFileSystem(engine);
|
||||
RegisterScriptHandle(engine);
|
||||
RegisterColor(engine);
|
||||
RegisterExceptionRoutines(engine);
|
||||
|
@ -92,6 +87,8 @@ bool ScriptMachine::configureEngine(asIScriptEngine *engine) {
|
|||
_rtypes.resize(RegisteredType::tMAXCOUNT);
|
||||
_rtypes[RegisteredType::tString] =
|
||||
q_check_ptr(_engine->GetTypeInfoByName("string"));
|
||||
_rtypes[RegisteredType::tChar] =
|
||||
q_check_ptr(_engine->GetTypeInfoByName("char"));
|
||||
_rtypes[RegisteredType::tArray] =
|
||||
q_check_ptr(_engine->GetTypeInfoByName("array"));
|
||||
_rtypes[RegisteredType::tComplex] =
|
||||
|
@ -108,15 +105,13 @@ bool ScriptMachine::configureEngine(asIScriptEngine *engine) {
|
|||
q_check_ptr(_engine->GetTypeInfoByName("dictionaryValue"));
|
||||
_rtypes[RegisteredType::tGrid] =
|
||||
q_check_ptr(_engine->GetTypeInfoByName("grid"));
|
||||
_rtypes[RegisteredType::tDateTime] =
|
||||
q_check_ptr(_engine->GetTypeInfoByName("datetime"));
|
||||
_rtypes[RegisteredType::tRef] =
|
||||
q_check_ptr(_engine->GetTypeInfoByName("ref"));
|
||||
|
||||
// Register a couple of extra functions for the scripts
|
||||
_printFn = std::bind(&ScriptMachine::print, this, std::placeholders::_1,
|
||||
std::placeholders::_2);
|
||||
r = engine->RegisterGlobalFunction("void print(? &in)",
|
||||
r = engine->RegisterGlobalFunction("void print(? &in obj)",
|
||||
asMETHOD(decltype(_printFn), operator()),
|
||||
asCALL_THISCALL_ASGLOBAL, &_printFn);
|
||||
Q_ASSERT(r >= 0);
|
||||
|
@ -133,7 +128,7 @@ bool ScriptMachine::configureEngine(asIScriptEngine *engine) {
|
|||
}
|
||||
|
||||
r = engine->RegisterGlobalFunction(
|
||||
"int exec(const string &in, const string &in)",
|
||||
"int exec(const string &in exe, const string &in params)",
|
||||
asFUNCTIONPR(execSystemCmd, (const std::string &, const std::string &),
|
||||
int),
|
||||
asCALL_CDECL);
|
||||
|
@ -143,7 +138,8 @@ bool ScriptMachine::configureEngine(asIScriptEngine *engine) {
|
|||
}
|
||||
|
||||
r = engine->RegisterGlobalFunction(
|
||||
"int exec(const string &in, const string &in, string &out)",
|
||||
"int exec(const string &in exe, const string &in params, "
|
||||
"string &out output)",
|
||||
asFUNCTIONPR(execSystemCmd,
|
||||
(const std::string &, const std::string &, std::string &),
|
||||
int),
|
||||
|
@ -172,15 +168,14 @@ bool ScriptMachine::configureEngine(asIScriptEngine *engine) {
|
|||
// strings
|
||||
_debugger->registerToStringCallback(_rtypes[RegisteredType::tString],
|
||||
&AngelObjString::stringToString);
|
||||
_debugger->registerToStringCallback(_rtypes[RegisteredType::tChar],
|
||||
&AngelObjString::charToString);
|
||||
_debugger->registerToStringCallback(_rtypes[RegisteredType::tArray],
|
||||
&AngelObjString::arrayToString);
|
||||
_debugger->registerToStringCallback(_rtypes[RegisteredType::tDictionary],
|
||||
&AngelObjString::dictionaryToString);
|
||||
_debugger->registerToStringCallback(_rtypes[RegisteredType::tDateTime],
|
||||
&AngelObjString::dateTimeToString);
|
||||
|
||||
PluginSystem::instance().angelApi()->installAPI(
|
||||
engine, typeInfo(RegisteredType::tString));
|
||||
PluginSystem::instance().angelApi()->installAPI(this);
|
||||
|
||||
_immediateContext = engine->CreateContext();
|
||||
_immediateContext->SetExceptionCallback(
|
||||
|
@ -218,7 +213,7 @@ void ScriptMachine::exceptionCallback(asIScriptContext *context) {
|
|||
tr("- Exception '%1' in '%2'\n")
|
||||
.arg(context->GetExceptionString(),
|
||||
context->GetExceptionFunction()->GetDeclaration()) +
|
||||
getCallStack(context);
|
||||
QStringLiteral("\n") + getCallStack(context);
|
||||
|
||||
const char *section;
|
||||
MessageInfo msg;
|
||||
|
@ -269,14 +264,14 @@ bool ScriptMachine::executeScript(const QString &script, bool isInDebug) {
|
|||
// ready to execute, so disable the automatic initialization
|
||||
_engine->SetEngineProperty(asEP_INIT_GLOBAL_VARS_AFTER_BUILD, false);
|
||||
|
||||
asBuilder builder;
|
||||
asBuilder builder(_engine);
|
||||
|
||||
// Set the pragma callback so we can detect
|
||||
builder.SetPragmaCallback(&ScriptMachine::pragmaCallback, this);
|
||||
builder.SetIncludeCallback(&ScriptMachine::includeCallback, this);
|
||||
|
||||
// Compile the script
|
||||
auto r = builder.StartNewModule(_engine, "script");
|
||||
auto r = builder.StartNewModule("script");
|
||||
if (r < 0) {
|
||||
return false;
|
||||
}
|
||||
|
@ -286,7 +281,7 @@ bool ScriptMachine::executeScript(const QString &script, bool isInDebug) {
|
|||
return false;
|
||||
}
|
||||
|
||||
r = builder.BuildModule();
|
||||
r = builder.Build();
|
||||
if (r < 0) {
|
||||
MessageInfo info;
|
||||
info.message = tr("Script failed to build");
|
||||
|
@ -406,7 +401,7 @@ bool ScriptMachine::executeScript(const QString &script, bool isInDebug) {
|
|||
}
|
||||
|
||||
void ScriptMachine::messageCallback(const asSMessageInfo *msg, void *param) {
|
||||
MessageType t;
|
||||
MessageType t = MessageType::Print;
|
||||
switch (msg->type) {
|
||||
case asMSGTYPE_ERROR:
|
||||
t = MessageType::Error;
|
||||
|
@ -491,7 +486,7 @@ void ScriptMachine::returnContextCallback(asIScriptEngine *engine,
|
|||
}
|
||||
|
||||
int ScriptMachine::pragmaCallback(const QByteArray &pragmaText,
|
||||
asBuilder *builder, void *userParam) {
|
||||
AsPreprocesser *builder, void *userParam) {
|
||||
// asIScriptEngine *engine = builder->GetEngine();
|
||||
|
||||
// Filter the pragmaText so only what is of interest remains
|
||||
|
@ -524,7 +519,7 @@ int ScriptMachine::pragmaCallback(const QByteArray &pragmaText,
|
|||
}
|
||||
|
||||
int ScriptMachine::includeCallback(const QString &include, bool quotedInclude,
|
||||
const QString &from, asBuilder *builder,
|
||||
const QString &from, AsPreprocesser *builder,
|
||||
void *userParam) {
|
||||
QFileInfo info(include);
|
||||
bool isAbsolute = info.isAbsolute();
|
||||
|
|
|
@ -42,9 +42,9 @@ public:
|
|||
QString message;
|
||||
};
|
||||
|
||||
protected:
|
||||
enum RegisteredType {
|
||||
tString,
|
||||
tChar,
|
||||
tArray,
|
||||
tComplex,
|
||||
tWeakref,
|
||||
|
@ -53,7 +53,6 @@ protected:
|
|||
tDictionary,
|
||||
tDictionaryValue,
|
||||
tGrid,
|
||||
tDateTime,
|
||||
tRef,
|
||||
tMAXCOUNT
|
||||
};
|
||||
|
@ -126,11 +125,11 @@ private:
|
|||
static void returnContextCallback(asIScriptEngine *engine,
|
||||
asIScriptContext *ctx, void *param);
|
||||
|
||||
static int pragmaCallback(const QByteArray &pragmaText, asBuilder *builder,
|
||||
void *userParam);
|
||||
static int pragmaCallback(const QByteArray &pragmaText,
|
||||
AsPreprocesser *builder, void *userParam);
|
||||
|
||||
static int includeCallback(const QString &include, bool quotedInclude,
|
||||
const QString &from, asBuilder *builder,
|
||||
const QString &from, AsPreprocesser *builder,
|
||||
void *userParam);
|
||||
|
||||
static QString processTranslation(const char *content);
|
||||
|
|
|
@ -19,8 +19,10 @@
|
|||
|
||||
#include "class/logger.h"
|
||||
#include "class/skinmanager.h"
|
||||
#include "qeditor.h"
|
||||
#include "settings/settings.h"
|
||||
#include "utilities.h"
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QMetaEnum>
|
||||
|
||||
|
@ -58,14 +60,33 @@ Q_GLOBAL_STATIC_WITH_ARGS(QString, SCRIPT_RECENTFILES, ("script.recentfiles"))
|
|||
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QString, SCRIPT_ALLOW_USRSCRIPT_INROOT,
|
||||
("script.allowUsrScriptRoot"))
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QString, SCRIPT_ENABLE, ("script.enable"))
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QString, SCRIPT_USRHIDECATS, ("script.usrHideCats"))
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QString, SCRIPT_SYSHIDECATS, ("script.sysHideCats"))
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QString, OTHER_USESYS_FILEDIALOG,
|
||||
("sys.nativeDialog"))
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QString, OTHER_USE_NATIVE_TITLEBAR,
|
||||
("sys.nativeTitleBar"))
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QString, OTHER_DONT_USE_SPLASH, ("sys.dontUseSplash"))
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QString, OTHER_LOG_LEVEL, ("sys.loglevel"))
|
||||
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QString, CODEEDIT_FONT, ("codeedit.font"))
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QString, CODEEDIT_FONT_SIZE, ("codeedit.fontsize"))
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QString, CODEEDIT_SHOW_LEADING_WHITESPACE,
|
||||
("codeedit.leading_whitespace"))
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QString, CODEEDIT_SHOW_TRAILING_WHITESPACE,
|
||||
("codeedit.trailing_whitespace"))
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QString, CODEEDIT_SHOW_TABS, ("codeedit.show_tabs"))
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QString, CODEEDIT_TABS_WIDTH, ("codeedit.tab_width"))
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QString, CODEEDIT_REPLACE_TABS,
|
||||
("codeedit.replace_tabs"))
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QString, CODEEDIT_REMOVE_TRAILING,
|
||||
("codeedit.remove_trailing"))
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QString, CODEEDIT_PRESERVE_TRAILING_INDENT,
|
||||
("codeedit.preserve_trailing_indent"))
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QString, CODEEDIT_LINE_ENDINGS,
|
||||
("codeedit.line_endings"))
|
||||
|
||||
SettingManager::SettingManager() {
|
||||
_defaultFont = qApp->font();
|
||||
qRegisterMetaType<RecentFileManager::RecentInfo>();
|
||||
|
@ -73,6 +94,7 @@ SettingManager::SettingManager() {
|
|||
qRegisterMetaTypeStreamOperators<RecentFileManager::RecentInfo>();
|
||||
#endif
|
||||
load();
|
||||
loadCodeEditorConfig();
|
||||
}
|
||||
|
||||
QString SettingManager::lastUsedPath() const { return m_lastUsedPath; }
|
||||
|
@ -111,6 +133,8 @@ void SettingManager::load() {
|
|||
READ_CONFIG_BOOL(m_editorShowHeader, EDITOR_SHOW_ADDR, true);
|
||||
READ_CONFIG_BOOL(m_editorShowcol, EDITOR_SHOW_COL, true);
|
||||
READ_CONFIG_BOOL(m_editorShowtext, EDITOR_SHOW_TEXT, true);
|
||||
|
||||
READ_CONFIG_BOOL(m_dontUseSplash, OTHER_DONT_USE_SPLASH, false);
|
||||
READ_CONFIG_BOOL(m_useNativeFileDialog, OTHER_USESYS_FILEDIALOG, true);
|
||||
#ifdef WINGHEX_USE_FRAMELESS
|
||||
READ_CONFIG_BOOL(m_useNativeTitleBar, OTHER_USE_NATIVE_TITLEBAR, false);
|
||||
|
@ -138,6 +162,7 @@ void SettingManager::load() {
|
|||
m_recentScriptFiles = getDataFromVarList(
|
||||
READ_CONFIG(SCRIPT_RECENTFILES, QVariantList()).toList());
|
||||
|
||||
READ_CONFIG_BOOL(m_scriptEnabled, SCRIPT_ENABLE, true);
|
||||
READ_CONFIG_BOOL(m_allowUsrScriptInRoot, SCRIPT_ALLOW_USRSCRIPT_INROOT,
|
||||
false);
|
||||
m_usrHideCats =
|
||||
|
@ -179,6 +204,24 @@ QVariantList SettingManager::getVarList(
|
|||
return varlist;
|
||||
}
|
||||
|
||||
bool SettingManager::dontUseSplash() const { return m_dontUseSplash; }
|
||||
|
||||
void SettingManager::setDontUseSplash(bool newDontUseSplash) {
|
||||
if (m_dontUseSplash != newDontUseSplash) {
|
||||
m_dontUseSplash = newDontUseSplash;
|
||||
_setUnsaved.setFlag(SETTING_ITEM::OTHER_DONT_USE_SPLASH);
|
||||
}
|
||||
}
|
||||
|
||||
bool SettingManager::scriptEnabled() const { return m_scriptEnabled; }
|
||||
|
||||
void SettingManager::setScriptEnabled(bool newScriptEnabled) {
|
||||
if (m_scriptEnabled != newScriptEnabled) {
|
||||
m_scriptEnabled = newScriptEnabled;
|
||||
_setUnsaved.setFlag(SETTING_ITEM::SCRIPT_ENABLE);
|
||||
}
|
||||
}
|
||||
|
||||
bool SettingManager::allowUsrScriptInRoot() const {
|
||||
return m_allowUsrScriptInRoot;
|
||||
}
|
||||
|
@ -190,6 +233,95 @@ void SettingManager::setAllowUsrScriptInRoot(bool newAllowUsrScriptInRoot) {
|
|||
}
|
||||
}
|
||||
|
||||
void SettingManager::loadCodeEditorConfig() {
|
||||
HANDLE_CONFIG;
|
||||
|
||||
auto dfont = qApp->font();
|
||||
QString fontName;
|
||||
READ_CONFIG_STRING(fontName, CODEEDIT_FONT, dfont.family());
|
||||
int pointSize;
|
||||
READ_CONFIG_INT_POSITIVE(pointSize, CODEEDIT_FONT_SIZE, dfont.pointSize());
|
||||
|
||||
dfont = QFont(fontName, pointSize);
|
||||
QEditor::setDefaultFont(dfont);
|
||||
|
||||
int tabStop;
|
||||
READ_CONFIG_INT_POSITIVE(tabStop, CODEEDIT_TABS_WIDTH, 4);
|
||||
QEditor::setDefaultTabStop(tabStop);
|
||||
|
||||
QDocument::WhiteSpaceMode ws = QDocument::ShowNone;
|
||||
|
||||
bool b;
|
||||
READ_CONFIG_BOOL(b, CODEEDIT_SHOW_TABS, false);
|
||||
|
||||
if (b)
|
||||
ws |= QDocument::ShowTabs;
|
||||
|
||||
READ_CONFIG_BOOL(b, CODEEDIT_SHOW_LEADING_WHITESPACE, false);
|
||||
if (b)
|
||||
ws |= QDocument::ShowLeading;
|
||||
|
||||
READ_CONFIG_BOOL(b, CODEEDIT_SHOW_TRAILING_WHITESPACE, false);
|
||||
if (b)
|
||||
ws |= QDocument::ShowTrailing;
|
||||
|
||||
QEditor::setDefaultShowSpaces(ws);
|
||||
|
||||
int enums;
|
||||
READ_CONFIG_INT(enums, CODEEDIT_LINE_ENDINGS,
|
||||
QDocument::LineEnding::Conservative);
|
||||
|
||||
auto le =
|
||||
QDocument::LineEnding(qMin(enums, int(QDocument::LineEnding::Mac)));
|
||||
QEditor::setDefaultLineEnding(le);
|
||||
|
||||
int flags = QEditor::defaultFlags();
|
||||
|
||||
READ_CONFIG_BOOL(b, CODEEDIT_REPLACE_TABS, true);
|
||||
if (b)
|
||||
flags |= QEditor::ReplaceTabs;
|
||||
else
|
||||
flags &= ~QEditor::ReplaceTabs;
|
||||
|
||||
READ_CONFIG_BOOL(b, CODEEDIT_REMOVE_TRAILING, true);
|
||||
if (b)
|
||||
flags |= QEditor::RemoveTrailing;
|
||||
else
|
||||
flags &= ~QEditor::RemoveTrailing;
|
||||
|
||||
READ_CONFIG_BOOL(b, CODEEDIT_PRESERVE_TRAILING_INDENT, false);
|
||||
if (b)
|
||||
flags |= QEditor::PreserveTrailingIndent;
|
||||
else
|
||||
flags &= ~QEditor::PreserveTrailingIndent;
|
||||
|
||||
QEditor::setDefaultFlags(flags);
|
||||
}
|
||||
|
||||
void SettingManager::saveCodeEditorConfig() {
|
||||
HANDLE_CONFIG;
|
||||
auto font = QEditor::defaultFont();
|
||||
WRITE_CONFIG(CODEEDIT_FONT, font.family());
|
||||
WRITE_CONFIG(CODEEDIT_FONT_SIZE, font.pointSize());
|
||||
|
||||
WRITE_CONFIG(CODEEDIT_TABS_WIDTH, QEditor::defaultTabStop());
|
||||
|
||||
auto showSpaces = QEditor::defaultShowSpaces();
|
||||
WRITE_CONFIG(CODEEDIT_SHOW_TABS, showSpaces.testFlag(QDocument::ShowTabs));
|
||||
WRITE_CONFIG(CODEEDIT_SHOW_LEADING_WHITESPACE,
|
||||
showSpaces.testFlag(QDocument::ShowLeading));
|
||||
WRITE_CONFIG(CODEEDIT_SHOW_TRAILING_WHITESPACE,
|
||||
showSpaces.testFlag(QDocument::ShowTrailing));
|
||||
|
||||
WRITE_CONFIG(CODEEDIT_LINE_ENDINGS, int(QEditor::defaultLineEnding()));
|
||||
|
||||
int flags = QEditor::defaultFlags();
|
||||
WRITE_CONFIG(CODEEDIT_REPLACE_TABS, flags & QEditor::ReplaceTabs);
|
||||
WRITE_CONFIG(CODEEDIT_REMOVE_TRAILING, flags & QEditor::RemoveTrailing);
|
||||
WRITE_CONFIG(CODEEDIT_PRESERVE_TRAILING_INDENT,
|
||||
flags & QEditor::PreserveTrailingIndent);
|
||||
}
|
||||
|
||||
void SettingManager::setUsrHideCats(const QStringList &newUsrHideCats) {
|
||||
if (m_usrHideCats != newUsrHideCats) {
|
||||
m_usrHideCats = newUsrHideCats;
|
||||
|
@ -348,6 +480,7 @@ void SettingManager::save(SETTINGS cat) {
|
|||
WRITE_CONFIG_SET(EDITOR_DECSTRLIMIT, m_decodeStrlimit);
|
||||
}
|
||||
if (cat.testFlag(SETTING::SCRIPT)) {
|
||||
WRITE_CONFIG_SET(SCRIPT_ENABLE, m_scriptEnabled);
|
||||
WRITE_CONFIG_SET(SCRIPT_ALLOW_USRSCRIPT_INROOT, m_allowUsrScriptInRoot);
|
||||
WRITE_CONFIG_SET(SCRIPT_USRHIDECATS, m_usrHideCats);
|
||||
WRITE_CONFIG_SET(SCRIPT_SYSHIDECATS, m_sysHideCats);
|
||||
|
@ -357,8 +490,12 @@ void SettingManager::save(SETTINGS cat) {
|
|||
#ifdef WINGHEX_USE_FRAMELESS
|
||||
WRITE_CONFIG_SET(OTHER_USE_NATIVE_TITLEBAR, m_useNativeTitleBar);
|
||||
#endif
|
||||
WRITE_CONFIG_SET(OTHER_DONT_USE_SPLASH, m_dontUseSplash);
|
||||
WRITE_CONFIG_SET(OTHER_LOG_LEVEL, m_logLevel);
|
||||
}
|
||||
if (cat.testFlag(SETTING::CODEEDIT)) {
|
||||
saveCodeEditorConfig();
|
||||
}
|
||||
}
|
||||
|
||||
void SettingManager::reset(SETTINGS cat) {
|
||||
|
@ -385,6 +522,7 @@ void SettingManager::reset(SETTINGS cat) {
|
|||
WRITE_CONFIG_SET(EDITOR_DECSTRLIMIT, 10);
|
||||
}
|
||||
if (cat.testFlag(SETTING::SCRIPT)) {
|
||||
WRITE_CONFIG_SET(SCRIPT_ENABLE, true);
|
||||
WRITE_CONFIG_SET(SCRIPT_ALLOW_USRSCRIPT_INROOT, false);
|
||||
WRITE_CONFIG_SET(SCRIPT_USRHIDECATS, QStringList());
|
||||
WRITE_CONFIG_SET(SCRIPT_SYSHIDECATS, QStringList());
|
||||
|
@ -394,6 +532,7 @@ void SettingManager::reset(SETTINGS cat) {
|
|||
#ifdef WINGHEX_USE_FRAMELESS
|
||||
WRITE_CONFIG_SET(OTHER_USE_NATIVE_TITLEBAR, false);
|
||||
#endif
|
||||
WRITE_CONFIG_SET(OTHER_DONT_USE_SPLASH, false);
|
||||
WRITE_CONFIG_SET(OTHER_LOG_LEVEL, Logger::defaultLevel());
|
||||
}
|
||||
load();
|
||||
|
|
|
@ -37,7 +37,8 @@ public:
|
|||
EDITOR = 4,
|
||||
SCRIPT = 8,
|
||||
OTHER = 16,
|
||||
ALL = APP | PLUGIN | EDITOR | SCRIPT | OTHER
|
||||
CODEEDIT = 32,
|
||||
ALL = APP | PLUGIN | EDITOR | SCRIPT | OTHER | CODEEDIT
|
||||
};
|
||||
Q_DECLARE_FLAGS(SETTINGS, SETTING)
|
||||
private:
|
||||
|
@ -65,12 +66,14 @@ private:
|
|||
EDITOR_DECSTRLIMIT = 1u << 17,
|
||||
EDITOR_RECENTFILES = 1u << 18,
|
||||
SCRIPT_RECENTFILES = 1u << 19,
|
||||
SCRIPT_ALLOW_USRSCRIPT_INROOT = 1u << 20,
|
||||
SCRIPT_USRHIDECATS = 1u << 21,
|
||||
SCRIPT_SYSHIDECATS = 1u << 22,
|
||||
OTHER_USESYS_FILEDIALOG = 1u << 23,
|
||||
OTHER_USE_NATIVE_TITLEBAR = 1u << 24,
|
||||
OTHER_LOG_LEVEL = 1u << 25
|
||||
SCRIPT_ENABLE = 1u << 20,
|
||||
SCRIPT_ALLOW_USRSCRIPT_INROOT = 1u << 21,
|
||||
SCRIPT_USRHIDECATS = 1u << 22,
|
||||
SCRIPT_SYSHIDECATS = 1u << 23,
|
||||
OTHER_USESYS_FILEDIALOG = 1u << 24,
|
||||
OTHER_USE_NATIVE_TITLEBAR = 1u << 25,
|
||||
OTHER_DONT_USE_SPLASH = 1u << 26,
|
||||
OTHER_LOG_LEVEL = 1u << 27
|
||||
};
|
||||
Q_DECLARE_FLAGS(SETTING_ITEMS, SETTING_ITEM)
|
||||
|
||||
|
@ -159,6 +162,12 @@ public:
|
|||
bool allowUsrScriptInRoot() const;
|
||||
void setAllowUsrScriptInRoot(bool newAllowUsrScriptInRoot);
|
||||
|
||||
bool scriptEnabled() const;
|
||||
void setScriptEnabled(bool newScriptEnabled);
|
||||
|
||||
bool dontUseSplash() const;
|
||||
void setDontUseSplash(bool newDontUseSplash);
|
||||
|
||||
signals:
|
||||
void sigEditorfontSizeChanged(int v);
|
||||
void sigDecodeStrlimitChanged(int v);
|
||||
|
@ -166,6 +175,10 @@ signals:
|
|||
|
||||
void logLevelChanged();
|
||||
|
||||
private:
|
||||
void loadCodeEditorConfig();
|
||||
void saveCodeEditorConfig();
|
||||
|
||||
private:
|
||||
SettingManager();
|
||||
|
||||
|
@ -200,12 +213,14 @@ private:
|
|||
QList<RecentFileManager::RecentInfo> m_recentScriptFiles;
|
||||
Qt::WindowState m_defaultWinState = Qt::WindowMaximized;
|
||||
|
||||
bool m_scriptEnabled = true;
|
||||
bool m_allowUsrScriptInRoot = false;
|
||||
QStringList m_usrHideCats;
|
||||
QStringList m_sysHideCats;
|
||||
|
||||
QString m_lastUsedPath;
|
||||
|
||||
bool m_dontUseSplash = false;
|
||||
bool m_useNativeFileDialog = true;
|
||||
bool m_useNativeTitleBar = false;
|
||||
int m_logLevel = 0;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -26,6 +26,7 @@
|
|||
#include <vector>
|
||||
|
||||
class asIScriptEngine;
|
||||
class ScriptMachine;
|
||||
|
||||
class WingAngelAPI : public WingHex::IWingPlugin {
|
||||
Q_OBJECT
|
||||
|
@ -46,7 +47,11 @@ public:
|
|||
virtual uint pluginVersion() const override;
|
||||
virtual const QString pluginComment() const override;
|
||||
|
||||
void installAPI(asIScriptEngine *engine, asITypeInfo *stringType);
|
||||
void
|
||||
registerScriptFns(const QString &ns,
|
||||
const QHash<QString, IWingPlugin::ScriptFnInfo> &rfns);
|
||||
|
||||
void installAPI(ScriptMachine *machine);
|
||||
|
||||
private:
|
||||
void installLogAPI(asIScriptEngine *engine);
|
||||
|
@ -59,6 +64,7 @@ private:
|
|||
void installHexReaderAPI(asIScriptEngine *engine);
|
||||
void installHexControllerAPI(asIScriptEngine *engine);
|
||||
void installDataVisualAPI(asIScriptEngine *engine, int stringID);
|
||||
void installScriptFns(asIScriptEngine *engine);
|
||||
|
||||
private:
|
||||
template <class T>
|
||||
|
@ -70,8 +76,11 @@ private:
|
|||
asCALL_THISCALL_ASGLOBAL,
|
||||
std::any_cast<std::function<T>>(&_fnbuffer.back()));
|
||||
Q_ASSERT(r >= 0);
|
||||
Q_UNUSED(r);
|
||||
}
|
||||
|
||||
using WrapperFn = std::function<void(asIScriptGeneric *)>;
|
||||
|
||||
private:
|
||||
QStringList cArray2QStringList(const CScriptArray &array, int stringID,
|
||||
bool *ok = nullptr);
|
||||
|
@ -82,6 +91,35 @@ private:
|
|||
|
||||
qsizetype getAsTypeSize(int typeId, void *data);
|
||||
|
||||
template <typename T>
|
||||
static void assignTmpBuffer(asQWORD &buffer, const T &v) {
|
||||
static_assert(std::is_pod<T>());
|
||||
static_assert(sizeof(T) <= sizeof(asQWORD));
|
||||
*reinterpret_cast<T *>(&buffer) = v;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static T qvariantCastGetValue(void *buffer) {
|
||||
static_assert(std::is_pod<T>());
|
||||
static_assert(sizeof(T) <= sizeof(asQWORD));
|
||||
return *reinterpret_cast<T *>(buffer);
|
||||
}
|
||||
|
||||
static void
|
||||
qvariantCastOp(asIScriptEngine *engine, const QVariant &var,
|
||||
const std::function<void(void *, QMetaType::Type)> &fn);
|
||||
|
||||
static QVariant qvariantGet(asIScriptEngine *engine, const void *raw,
|
||||
int typeID);
|
||||
|
||||
static int qvariantCastASID(asIScriptEngine *engine,
|
||||
const QMetaType::Type &id);
|
||||
|
||||
static bool isTempBuffered(QMetaType::Type type);
|
||||
|
||||
void script_call(asIScriptEngine *engine, qsizetype id,
|
||||
asIScriptGeneric *gen);
|
||||
|
||||
private:
|
||||
QString _InputBox_getItem(int stringID, const QString &title,
|
||||
const QString &label, const CScriptArray &items,
|
||||
|
@ -136,6 +174,10 @@ private:
|
|||
|
||||
private:
|
||||
std::vector<std::any> _fnbuffer;
|
||||
QVector<IWingPlugin::ScriptFnInfo> _sfns;
|
||||
QHash<asIScriptEngine *, std::vector<WrapperFn>> _sfn_wraps;
|
||||
|
||||
QHash<QString, QHash<QString, qsizetype>> _rfns;
|
||||
};
|
||||
|
||||
#endif // WINGANGELAPI_H
|
||||
|
|
|
@ -17,27 +17,108 @@
|
|||
|
||||
#include "wingprogressdialog.h"
|
||||
|
||||
#include <QProgressBar>
|
||||
|
||||
WingProgressDialog::WingProgressDialog(QWidget *parent) {
|
||||
m_dialog = new QProgressDialog(parent, Qt::Widget);
|
||||
auto pb = new QProgressBar(this);
|
||||
pb->setTextVisible(false);
|
||||
m_dialog->setBar(pb);
|
||||
|
||||
buildUpContent(m_dialog);
|
||||
connect(m_dialog, &QProgressDialog::canceled, this,
|
||||
&WingProgressDialog::canceled);
|
||||
connect(m_dialog, &QProgressDialog::finished, this,
|
||||
&FramelessDialogBase::done);
|
||||
}
|
||||
|
||||
WingProgressDialog::WingProgressDialog(const QString &labelText,
|
||||
const QString &cancelButtonText,
|
||||
int minimum, int maximum,
|
||||
QWidget *parent) {
|
||||
m_dialog = new QProgressDialog(labelText, cancelButtonText, minimum,
|
||||
maximum, parent);
|
||||
maximum, this);
|
||||
m_dialog->setWindowFlag(Qt::Widget);
|
||||
auto pb = new QProgressBar(this);
|
||||
pb->setTextVisible(false);
|
||||
m_dialog->setBar(pb);
|
||||
|
||||
m_d = new FramelessDialogBase(parent);
|
||||
m_d->buildUpContent(m_dialog);
|
||||
m_d->setWindowTitle(labelText);
|
||||
buildUpContent(m_dialog);
|
||||
|
||||
QObject::connect(m_dialog, &QProgressDialog::finished, m_d,
|
||||
&FramelessDialogBase::done);
|
||||
connect(m_dialog, &QProgressDialog::canceled, this,
|
||||
&WingProgressDialog::canceled);
|
||||
connect(m_dialog, &QProgressDialog::finished, this,
|
||||
&FramelessDialogBase::done);
|
||||
}
|
||||
|
||||
WingProgressDialog::~WingProgressDialog() {
|
||||
delete m_dialog;
|
||||
delete m_d;
|
||||
WingProgressDialog::~WingProgressDialog() {}
|
||||
|
||||
void WingProgressDialog::setLabel(QLabel *label) { m_dialog->setLabel(label); }
|
||||
|
||||
void WingProgressDialog::setCancelButton(QPushButton *button) {
|
||||
m_dialog->setCancelButton(button);
|
||||
}
|
||||
|
||||
FramelessDialogBase *WingProgressDialog::pdialog() const { return m_d; }
|
||||
void WingProgressDialog::setBar(QProgressBar *bar) { m_dialog->setBar(bar); }
|
||||
|
||||
QProgressDialog *WingProgressDialog::dialog() const { return m_dialog; }
|
||||
bool WingProgressDialog::wasCanceled() const { return m_dialog->wasCanceled(); }
|
||||
|
||||
int WingProgressDialog::minimum() const { return m_dialog->minimum(); }
|
||||
|
||||
int WingProgressDialog::maximum() const { return m_dialog->maximum(); }
|
||||
|
||||
int WingProgressDialog::value() const { return m_dialog->value(); }
|
||||
|
||||
QString WingProgressDialog::labelText() const { return m_dialog->labelText(); }
|
||||
|
||||
int WingProgressDialog::minimumDuration() const {
|
||||
return m_dialog->minimumDuration();
|
||||
}
|
||||
|
||||
void WingProgressDialog::setAutoReset(bool reset) {
|
||||
m_dialog->setAutoReset(reset);
|
||||
}
|
||||
|
||||
bool WingProgressDialog::autoReset() const { return m_dialog->autoReset(); }
|
||||
|
||||
void WingProgressDialog::setAutoClose(bool close) {
|
||||
m_dialog->setAutoClose(close);
|
||||
}
|
||||
|
||||
bool WingProgressDialog::autoClose() const { return m_dialog->autoClose(); }
|
||||
|
||||
void WingProgressDialog::open(QObject *receiver, const char *member) {
|
||||
m_dialog->open(receiver, member);
|
||||
}
|
||||
|
||||
void WingProgressDialog::cancel() { m_dialog->cancel(); }
|
||||
|
||||
void WingProgressDialog::reset() { m_dialog->reset(); }
|
||||
|
||||
void WingProgressDialog::setMaximum(int maximum) {
|
||||
m_dialog->setMaximum(maximum);
|
||||
}
|
||||
|
||||
void WingProgressDialog::setMinimum(int minimum) {
|
||||
m_dialog->setMinimum(minimum);
|
||||
}
|
||||
|
||||
void WingProgressDialog::setRange(int minimum, int maximum) {
|
||||
m_dialog->setRange(minimum, maximum);
|
||||
}
|
||||
|
||||
void WingProgressDialog::setValue(int progress) {
|
||||
m_dialog->setValue(progress);
|
||||
}
|
||||
|
||||
void WingProgressDialog::setLabelText(const QString &text) {
|
||||
m_dialog->setLabelText(text);
|
||||
}
|
||||
|
||||
void WingProgressDialog::setCancelButtonText(const QString &text) {
|
||||
m_dialog->setCancelButtonText(text);
|
||||
}
|
||||
|
||||
void WingProgressDialog::setMinimumDuration(int ms) {
|
||||
m_dialog->setMinimumDuration(ms);
|
||||
}
|
||||
|
|
|
@ -20,21 +20,59 @@
|
|||
|
||||
#include <QProgressDialog>
|
||||
|
||||
#include "../dialog/framelessdialogbase.h"
|
||||
#include "dialog/framelessdialogbase.h"
|
||||
|
||||
class WingProgressDialog : public FramelessDialogBase {
|
||||
Q_OBJECT
|
||||
|
||||
class WingProgressDialog {
|
||||
public:
|
||||
explicit WingProgressDialog(QWidget *parent = nullptr);
|
||||
|
||||
WingProgressDialog(const QString &labelText,
|
||||
const QString &cancelButtonText, int minimum,
|
||||
int maximum, QWidget *parent = nullptr);
|
||||
~WingProgressDialog();
|
||||
|
||||
FramelessDialogBase *pdialog() const;
|
||||
QProgressDialog *dialog() const;
|
||||
public:
|
||||
void setLabel(QLabel *label);
|
||||
void setCancelButton(QPushButton *button);
|
||||
void setBar(QProgressBar *bar);
|
||||
|
||||
bool wasCanceled() const;
|
||||
|
||||
int minimum() const;
|
||||
int maximum() const;
|
||||
|
||||
int value() const;
|
||||
|
||||
QString labelText() const;
|
||||
int minimumDuration() const;
|
||||
|
||||
void setAutoReset(bool reset);
|
||||
bool autoReset() const;
|
||||
void setAutoClose(bool close);
|
||||
bool autoClose() const;
|
||||
|
||||
using FramelessDialogBase::open;
|
||||
|
||||
void open(QObject *receiver, const char *member);
|
||||
|
||||
public Q_SLOTS:
|
||||
void cancel();
|
||||
void reset();
|
||||
void setMaximum(int maximum);
|
||||
void setMinimum(int minimum);
|
||||
void setRange(int minimum, int maximum);
|
||||
void setValue(int progress);
|
||||
void setLabelText(const QString &text);
|
||||
void setCancelButtonText(const QString &text);
|
||||
void setMinimumDuration(int ms);
|
||||
|
||||
Q_SIGNALS:
|
||||
void canceled();
|
||||
|
||||
private:
|
||||
QProgressDialog *m_dialog;
|
||||
FramelessDialogBase *m_d;
|
||||
};
|
||||
|
||||
#endif // WINGPROGRESSDIALOG_H
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
/*==============================================================================
|
||||
** 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 "asobjtreewidget.h"
|
||||
|
||||
#include "class/qasparser.h"
|
||||
|
||||
#include <QHeaderView>
|
||||
|
||||
ASObjTreeWidget::ASObjTreeWidget(QWidget *parent) : QTreeWidget(parent) {
|
||||
setColumnCount(2);
|
||||
header()->setDefaultAlignment(Qt::AlignCenter);
|
||||
setHeaderLabels({tr("Symbol"), tr("Decl")});
|
||||
}
|
||||
|
||||
void ASObjTreeWidget::setEngine(asIScriptEngine *engine) {
|
||||
Q_ASSERT(engine);
|
||||
if (engine == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
QAsParser parser(engine);
|
||||
auto &nodes = parser.headerNodes();
|
||||
for (auto &node : nodes) {
|
||||
auto header = QString::fromUtf8(node->role(QCodeNode::Name));
|
||||
|
||||
QTreeWidgetItem *item = nullptr;
|
||||
|
||||
if (header.isEmpty()) {
|
||||
item = new QTreeWidgetItem({tr("[Global]")});
|
||||
} else {
|
||||
item = new QTreeWidgetItem({header});
|
||||
}
|
||||
|
||||
item->setToolTip(0, node->qualifiedBaseName(true));
|
||||
item->setIcon(0, node->data(Qt::DecorationRole).value<QIcon>());
|
||||
|
||||
createObjNodes(node->children(), item);
|
||||
addTopLevelItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
QTreeWidgetItem *ASObjTreeWidget::createObjNode(QCodeNode *node,
|
||||
QTreeWidgetItem *parent) {
|
||||
Q_ASSERT(node && parent);
|
||||
QStringList contents{QString::fromUtf8(node->role(QCodeNode::Name)),
|
||||
node->data(Qt::ToolTipRole).toString()};
|
||||
auto c = new QTreeWidgetItem(contents);
|
||||
c->setToolTip(0, contents.at(0));
|
||||
c->setToolTip(1, contents.at(1));
|
||||
c->setIcon(0, node->data(Qt::DecorationRole).value<QIcon>());
|
||||
parent->addChild(c);
|
||||
return c;
|
||||
}
|
||||
|
||||
void ASObjTreeWidget::createObjNodes(const QList<QCodeNode *> &children,
|
||||
QTreeWidgetItem *parent) {
|
||||
for (auto &n : children) {
|
||||
// only for code namespace completion
|
||||
if (n->role(QCodeNode::NodeType).at(0) == QCodeNode::Namespace) {
|
||||
if (n->children().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
auto c = createObjNode(n, parent);
|
||||
if (!n->children().isEmpty()) {
|
||||
createObjNodes(n->children(), c);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*==============================================================================
|
||||
** 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 ASOBJTREEWIDGET_H
|
||||
#define ASOBJTREEWIDGET_H
|
||||
|
||||
#include "angelscript.h"
|
||||
#include "class/qcodenode.h"
|
||||
|
||||
#include <QHash>
|
||||
#include <QTreeWidget>
|
||||
#include <QTreeWidgetItem>
|
||||
|
||||
class ASObjTreeWidget : public QTreeWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ASObjTreeWidget(QWidget *parent = nullptr);
|
||||
|
||||
void setEngine(asIScriptEngine *engine);
|
||||
|
||||
private:
|
||||
QTreeWidgetItem *createObjNode(QCodeNode *node, QTreeWidgetItem *parent);
|
||||
|
||||
void createObjNodes(const QList<QCodeNode *> &children,
|
||||
QTreeWidgetItem *parent);
|
||||
};
|
||||
|
||||
#endif // ASOBJTREEWIDGET_H
|
|
@ -0,0 +1,48 @@
|
|||
/*==============================================================================
|
||||
** 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 "codeedit.h"
|
||||
#include "qlinemarkpanel.h"
|
||||
#include "qlinenumberpanel.h"
|
||||
#include "qpanellayout.h"
|
||||
|
||||
#include "qeditor.h"
|
||||
|
||||
CodeEdit::CodeEdit(bool haslineMark, QWidget *parent, bool actions)
|
||||
: QObject(parent), QCodeEdit(actions, parent) {
|
||||
auto l = this->panelLayout();
|
||||
l->setSizeConstraint(QLayout::SetMinimumSize);
|
||||
|
||||
auto editor = this->editor();
|
||||
if (haslineMark) {
|
||||
auto lineMark = new QLineMarkPanel(editor);
|
||||
this->addPanel(lineMark, QCodeEdit::West);
|
||||
connect(lineMark, &QLineMarkPanel::onToggleMark, this,
|
||||
&CodeEdit::onToggleMark);
|
||||
}
|
||||
|
||||
auto lineNum = new QLineNumberPanel(editor);
|
||||
lineNum->setVerboseMode(true);
|
||||
this->addPanel(lineNum, QCodeEdit::West, true);
|
||||
connect(editor, &QEditor::cursorPositionChanged, lineNum,
|
||||
QOverload<>::of(&QLineMarkPanel::update));
|
||||
|
||||
this->addPanel(QStringLiteral("Fold Panel"), QCodeEdit::West, true);
|
||||
this->addPanel(QStringLiteral("Line Change Panel"), QCodeEdit::West, true);
|
||||
this->addPanel(QStringLiteral("Goto Line Panel"), QCodeEdit::South);
|
||||
this->addPanel(QStringLiteral("Search Replace Panel"), QCodeEdit::South);
|
||||
}
|
|
@ -15,12 +15,21 @@
|
|||
** =============================================================================
|
||||
*/
|
||||
|
||||
#include "scriptbehaviorsettingdialog.h"
|
||||
#include "ui_scriptbehaviorsettingdialog.h"
|
||||
#ifndef CODEEDIT_H
|
||||
#define CODEEDIT_H
|
||||
|
||||
ScriptBehaviorSettingDialog::ScriptBehaviorSettingDialog(QWidget *parent)
|
||||
: QWidget(parent), ui(new Ui::ScriptBehaviorSettingDialog) {
|
||||
ui->setupUi(this);
|
||||
}
|
||||
#include "qcodeedit.h"
|
||||
|
||||
ScriptBehaviorSettingDialog::~ScriptBehaviorSettingDialog() { delete ui; }
|
||||
#include <QObject>
|
||||
|
||||
class CodeEdit : public QObject, public QCodeEdit {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CodeEdit(bool haslineMark, QWidget *parent = nullptr,
|
||||
bool actions = true);
|
||||
|
||||
signals:
|
||||
void onToggleMark(int lineIndex);
|
||||
};
|
||||
|
||||
#endif // CODEEDIT_H
|
|
@ -52,10 +52,11 @@ QCodeCompletionWidget::QCodeCompletionWidget(QEditor *p)
|
|||
pModel = new QCodeCompletionModel(this);
|
||||
setModel(pModel);
|
||||
|
||||
connect(pModel, SIGNAL(changed()), this, SLOT(changed()));
|
||||
connect(pModel, &QCodeCompletionModel::changed, this,
|
||||
&QCodeCompletionWidget::changed);
|
||||
|
||||
connect(this, SIGNAL(activated(QModelIndex)), this,
|
||||
SLOT(complete(QModelIndex)));
|
||||
connect(this, &QCodeCompletionWidget::activated, this,
|
||||
&QCodeCompletionWidget::complete);
|
||||
}
|
||||
|
||||
void QCodeCompletionWidget::changed() {
|
||||
|
@ -424,6 +425,7 @@ void QCodeCompletionModel::forceUpdate() const {
|
|||
|
||||
emit const_cast<QCodeCompletionModel *>(this)->layoutChanged();
|
||||
bUpdate = false;
|
||||
emit const_cast<QCodeCompletionModel *>(this)->changed();
|
||||
}
|
||||
|
||||
QList<QCodeNode *> QCodeCompletionModel::focusNodes() const { return m_nodes; }
|
||||
|
|
|
@ -53,6 +53,8 @@ public:
|
|||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
|
||||
signals:
|
||||
void changed();
|
||||
|
||||
void prefixChanged(const QString &newPrefix);
|
||||
void filterChanged(QCodeCompletionWidget::Filter f);
|
||||
|
||||
|
|
|
@ -16,17 +16,17 @@
|
|||
*/
|
||||
|
||||
#include "scripteditor.h"
|
||||
#include "qcodeeditwidget/qdocumentswaptextcommand.h"
|
||||
#include "qeditor.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QFile>
|
||||
#include <QPixmap>
|
||||
|
||||
#include "qlanguagefactory.h"
|
||||
#include "qlinemarkpanel.h"
|
||||
#include "qlinenumberpanel.h"
|
||||
#include "qpanellayout.h"
|
||||
|
||||
#include "class/clangformatmanager.h"
|
||||
|
||||
ScriptEditor::ScriptEditor(QWidget *parent)
|
||||
: ads::CDockWidget(QString(), parent) {
|
||||
this->setFeatures(
|
||||
|
@ -36,9 +36,9 @@ ScriptEditor::ScriptEditor(QWidget *parent)
|
|||
this->setFocusPolicy(Qt::StrongFocus);
|
||||
this->setObjectName(QStringLiteral("ScriptEditor"));
|
||||
|
||||
m_editor = new QCodeEdit(this);
|
||||
auto l = m_editor->panelLayout();
|
||||
l->setSizeConstraint(QLayout::SetMinimumSize);
|
||||
m_editor = new CodeEdit(true, this);
|
||||
connect(m_editor, &CodeEdit::onToggleMark, this,
|
||||
&ScriptEditor::onToggleMark);
|
||||
|
||||
auto editor = m_editor->editor();
|
||||
connect(editor, &QEditor::titleChanged, this, &ScriptEditor::processTitle);
|
||||
|
@ -46,42 +46,28 @@ ScriptEditor::ScriptEditor(QWidget *parent)
|
|||
&ScriptEditor::processTitle);
|
||||
|
||||
this->setWidget(editor);
|
||||
|
||||
auto lineMark = new QLineMarkPanel(editor);
|
||||
m_editor->addPanel(lineMark, QCodeEdit::West, true);
|
||||
connect(lineMark, &QLineMarkPanel::onToggleMark, this,
|
||||
&ScriptEditor::onToggleMark);
|
||||
|
||||
auto lineNum = new QLineNumberPanel(editor);
|
||||
lineNum->setVerboseMode(true);
|
||||
m_editor->addPanel(lineNum, QCodeEdit::West, true);
|
||||
|
||||
m_editor->addPanel(QStringLiteral("Fold Panel"), QCodeEdit::West, true);
|
||||
m_editor->addPanel(QStringLiteral("Line Change Panel"), QCodeEdit::West,
|
||||
true);
|
||||
m_editor->addPanel(QStringLiteral("Goto Line Panel"), QCodeEdit::South,
|
||||
true);
|
||||
m_editor->addPanel(QStringLiteral("Search Replace Panel"), QCodeEdit::South,
|
||||
true);
|
||||
}
|
||||
|
||||
ScriptEditor::~ScriptEditor() {
|
||||
auto e = m_editor->editor();
|
||||
auto e = editor();
|
||||
e->disconnect();
|
||||
e->document()->disconnect();
|
||||
}
|
||||
|
||||
QString ScriptEditor::fileName() const {
|
||||
return m_editor->editor()->fileName();
|
||||
}
|
||||
QString ScriptEditor::fileName() const { return editor()->fileName(); }
|
||||
|
||||
bool ScriptEditor::openFile(const QString &filename) {
|
||||
auto e = m_editor->editor();
|
||||
auto e = editor();
|
||||
return e->load(filename);
|
||||
}
|
||||
|
||||
bool ScriptEditor::save(const QString &path) {
|
||||
auto e = m_editor->editor();
|
||||
auto e = editor();
|
||||
auto clang = ClangFormatManager::instance();
|
||||
if (clang.exists() && clang.autoFormat()) {
|
||||
formatCode();
|
||||
}
|
||||
|
||||
if (path.isEmpty()) {
|
||||
return e->save();
|
||||
}
|
||||
|
@ -103,3 +89,15 @@ void ScriptEditor::processTitle() {
|
|||
}
|
||||
|
||||
QEditor *ScriptEditor::editor() const { return m_editor->editor(); }
|
||||
|
||||
bool ScriptEditor::formatCode() {
|
||||
bool ok;
|
||||
auto e = editor();
|
||||
auto fmtcodes = ClangFormatManager::instance().formatCode(e->text(), ok);
|
||||
if (ok) {
|
||||
auto doc = e->document();
|
||||
doc->execute(new QDocumentSwapTextCommand(fmtcodes, doc));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#define SCRIPTEDITOR_H
|
||||
|
||||
#include "Qt-Advanced-Docking-System/src/DockWidget.h"
|
||||
#include "control/codeedit.h"
|
||||
#include "qcodeedit.h"
|
||||
|
||||
class ScriptEditor : public ads::CDockWidget {
|
||||
|
@ -32,6 +33,8 @@ public:
|
|||
|
||||
QEditor *editor() const;
|
||||
|
||||
bool formatCode();
|
||||
|
||||
signals:
|
||||
void onToggleMark(int lineIndex);
|
||||
|
||||
|
@ -45,7 +48,7 @@ private:
|
|||
void processTitle();
|
||||
|
||||
private:
|
||||
QCodeEdit *m_editor = nullptr;
|
||||
CodeEdit *m_editor = nullptr;
|
||||
};
|
||||
|
||||
#endif // SCRIPTEDITOR_H
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "scriptingconsole.h"
|
||||
#include "class/scriptconsolemachine.h"
|
||||
#include "qregularexpression.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QColor>
|
||||
|
@ -41,6 +42,8 @@ void ScriptingConsole::stdWarn(const QString &str) {
|
|||
void ScriptingConsole::newLine() { _s << Qt::endl; }
|
||||
|
||||
void ScriptingConsole::init() {
|
||||
_s.setDevice(this->device());
|
||||
|
||||
_getInputFn = std::bind(&ScriptingConsole::getInput, this);
|
||||
|
||||
_sp = new ScriptConsoleMachine(_getInputFn, this);
|
||||
|
@ -53,14 +56,17 @@ void ScriptingConsole::init() {
|
|||
switch (type) {
|
||||
case ScriptMachine::MessageType::Info:
|
||||
stdOut(tr("[Info]") + message.message);
|
||||
_s << Qt::flush;
|
||||
newLine();
|
||||
break;
|
||||
case ScriptMachine::MessageType::Warn:
|
||||
stdWarn(tr("[Warn]") + message.message);
|
||||
_s << Qt::flush;
|
||||
newLine();
|
||||
break;
|
||||
case ScriptMachine::MessageType::Error:
|
||||
stdErr(tr("[Error]") + message.message);
|
||||
_s << Qt::flush;
|
||||
newLine();
|
||||
break;
|
||||
case ScriptMachine::MessageType::Print:
|
||||
|
@ -70,11 +76,10 @@ void ScriptingConsole::init() {
|
|||
});
|
||||
|
||||
connect(this, &QConsoleWidget::consoleCommand, this,
|
||||
&ScriptingConsole::consoleCommand);
|
||||
&ScriptingConsole::runConsoleCommand);
|
||||
}
|
||||
|
||||
void ScriptingConsole::initOutput() {
|
||||
_s.setDevice(this->device());
|
||||
stdWarn(tr("Scripting console for WingHexExplorer"));
|
||||
|
||||
_s << Qt::endl;
|
||||
|
@ -96,17 +101,28 @@ void ScriptingConsole::pushInputCmd(const QString &cmd) {
|
|||
_cmdQueue.append(cmd);
|
||||
}
|
||||
|
||||
void ScriptingConsole::consoleCommand(const QString &code) {
|
||||
void ScriptingConsole::runConsoleCommand(const QString &code) {
|
||||
if (_waitforRead) {
|
||||
_waitforRead = false;
|
||||
return;
|
||||
}
|
||||
|
||||
setMode(Output);
|
||||
if (!_sp->executeCode(code)) {
|
||||
auto exec = code.trimmed();
|
||||
if (exec.endsWith('\\')) {
|
||||
static QRegularExpression ex(QStringLiteral("[\\\\\\s]+$"));
|
||||
_codes += exec.remove(ex);
|
||||
setMode(Output);
|
||||
appendCommandPrompt(true);
|
||||
setMode(Input);
|
||||
} else {
|
||||
setMode(Output);
|
||||
_codes += exec;
|
||||
if (!_sp->executeCode(_codes)) {
|
||||
}
|
||||
_codes.clear();
|
||||
appendCommandPrompt();
|
||||
setMode(Input);
|
||||
}
|
||||
appendCommandPrompt();
|
||||
setMode(Input);
|
||||
}
|
||||
|
||||
QString ScriptingConsole::getInput() {
|
||||
|
|
|
@ -52,7 +52,7 @@ public slots:
|
|||
void pushInputCmd(const QString &cmd);
|
||||
|
||||
private:
|
||||
void consoleCommand(const QString &code);
|
||||
void runConsoleCommand(const QString &code);
|
||||
|
||||
QString getInput();
|
||||
|
||||
|
@ -61,6 +61,7 @@ private:
|
|||
QTextStream _s;
|
||||
|
||||
bool _lastCommandPrompt = false;
|
||||
QString _codes;
|
||||
|
||||
QStringList _cmdQueue;
|
||||
QMutex _queueLocker;
|
||||
|
|
|
@ -29,7 +29,6 @@ AboutSoftwareDialog::AboutSoftwareDialog(QWidget *parent)
|
|||
ui->tbBaseObj->setMarkdown(data.component);
|
||||
ui->tbCredit->setMarkdown(data.credit);
|
||||
ui->tbDev->setMarkdown(data.dev);
|
||||
ui->tbTr->setMarkdown(data.trans);
|
||||
ui->lblVersion->setText(qApp->applicationVersion());
|
||||
ui->lblBuildDate->setText(QStringLiteral(__DATE__));
|
||||
|
||||
|
@ -40,6 +39,13 @@ AboutSoftwareDialog::AboutSoftwareDialog(QWidget *parent)
|
|||
auto ltxt = license.readAll();
|
||||
ui->tbLicense->setText(ltxt);
|
||||
|
||||
QFile trans(QStringLiteral(":/com.wingsummer.winghex/src/translist.md"));
|
||||
ret = trans.open(QFile::ReadOnly);
|
||||
Q_ASSERT(ret);
|
||||
Q_UNUSED(ret);
|
||||
auto ttxt = trans.readAll();
|
||||
ui->tbTr->setMarkdown(ttxt);
|
||||
|
||||
_dialog = new FramelessDialogBase(parent);
|
||||
_dialog->buildUpContent(this);
|
||||
_dialog->setWindowTitle(this->windowTitle());
|
||||
|
|
|
@ -34,9 +34,9 @@ EncodingDialog::EncodingDialog(QWidget *parent) : FramelessDialogBase(parent) {
|
|||
layout->addWidget(l);
|
||||
layout->addSpacing(5);
|
||||
enclist = new QListWidget(this);
|
||||
for (auto &item : Utilities::getEncodings()) {
|
||||
enclist->addItem(item);
|
||||
}
|
||||
enclist->addItems(Utilities::getEncodings());
|
||||
enclist->setCurrentRow(0);
|
||||
|
||||
layout->addWidget(enclist);
|
||||
layout->addSpacing(10);
|
||||
auto dbbox = new QDialogButtonBox(
|
||||
|
|
|
@ -28,6 +28,9 @@
|
|||
#include <QVBoxLayout>
|
||||
|
||||
FramelessDialogBase::FramelessDialogBase(QWidget *parent) : QDialog(parent) {
|
||||
setWindowFlag(Qt::WindowMaximizeButtonHint, false);
|
||||
setWindowFlag(Qt::WindowMinimizeButtonHint, false);
|
||||
|
||||
#ifdef WINGHEX_USE_FRAMELESS
|
||||
_useFrameLess = !SettingManager::instance().useNativeTitleBar();
|
||||
if (_useFrameLess) {
|
||||
|
|
|
@ -69,11 +69,13 @@
|
|||
|
||||
constexpr auto EMPTY_FUNC = [] {};
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent) : FramelessMainWindow(parent) {
|
||||
MainWindow::MainWindow(SplashDialog *splash) : FramelessMainWindow() {
|
||||
this->setUpdatesEnabled(false);
|
||||
this->setMinimumSize(900, 800);
|
||||
|
||||
// recent file manager init
|
||||
if (splash)
|
||||
splash->setInfoText(tr("SetupRecent"));
|
||||
m_recentMenu = new QMenu(this);
|
||||
m_recentmanager = new RecentFileManager(m_recentMenu, false);
|
||||
connect(m_recentmanager, &RecentFileManager::triggered, this,
|
||||
|
@ -83,6 +85,8 @@ MainWindow::MainWindow(QWidget *parent) : FramelessMainWindow(parent) {
|
|||
});
|
||||
m_recentmanager->apply(this, SettingManager::instance().recentHexFiles());
|
||||
|
||||
if (splash)
|
||||
splash->setInfoText(tr("SetupUI"));
|
||||
// build up UI
|
||||
buildUpRibbonBar();
|
||||
|
||||
|
@ -94,6 +98,8 @@ MainWindow::MainWindow(QWidget *parent) : FramelessMainWindow(parent) {
|
|||
layout->setSpacing(0);
|
||||
layout->addWidget(q_check_ptr(m_ribbon));
|
||||
|
||||
if (splash)
|
||||
splash->setInfoText(tr("SetupDocking"));
|
||||
buildUpDockSystem(cw);
|
||||
_defaultLayout = m_dock->saveState();
|
||||
|
||||
|
@ -133,30 +139,50 @@ MainWindow::MainWindow(QWidget *parent) : FramelessMainWindow(parent) {
|
|||
auto &set = SettingManager::instance();
|
||||
|
||||
// launch logging system
|
||||
if (splash)
|
||||
splash->setInfoText(tr("LaunchingLog"));
|
||||
auto &log = Logger::instance();
|
||||
log.setLogLevel(Logger::Level(set.logLevel()));
|
||||
connect(&log, &Logger::log, m_logbrowser, &QTextBrowser::append);
|
||||
|
||||
// launch plugin system
|
||||
if (splash)
|
||||
splash->setInfoText(tr("SetupPluginSystem"));
|
||||
auto &plg = PluginSystem::instance();
|
||||
connect(&plg, &PluginSystem::pluginLoading, this,
|
||||
[=](const QString &plgName) {
|
||||
if (splash)
|
||||
splash->setInfoText(tr("LoadingPlg:") + plgName);
|
||||
});
|
||||
plg.setMainWindow(this);
|
||||
plg.LoadPlugin();
|
||||
// At this time, AngelScript service plugin has started
|
||||
m_scriptConsole->init();
|
||||
ScriptManager::instance().attach(m_scriptConsole);
|
||||
|
||||
auto &langins = LangService::instance();
|
||||
langins.init(m_scriptConsole->machine()->engine());
|
||||
langins.applyLanguageSerivce(m_scriptConsole);
|
||||
if (set.scriptEnabled()) {
|
||||
// At this time, AngelScript service plugin has started
|
||||
if (splash)
|
||||
splash->setInfoText(tr("SetupConsole"));
|
||||
m_scriptConsole->init();
|
||||
if (splash)
|
||||
splash->setInfoText(tr("SetupScriptManager"));
|
||||
ScriptManager::instance().attach(m_scriptConsole);
|
||||
|
||||
m_scriptConsole->initOutput();
|
||||
if (splash)
|
||||
splash->setInfoText(tr("SetupScriptService"));
|
||||
auto &langins = LangService::instance();
|
||||
langins.init(m_scriptConsole->machine()->engine());
|
||||
langins.applyLanguageSerivce(m_scriptConsole);
|
||||
|
||||
m_scriptDialog = new ScriptingDialog(this);
|
||||
m_scriptDialog->initConsole();
|
||||
m_scriptConsole->initOutput();
|
||||
|
||||
// load the model
|
||||
Q_ASSERT(m_scriptConsole && m_scriptConsole->machine());
|
||||
m_varshowtable->setModel(m_scriptConsole->consoleMachine()->model());
|
||||
if (splash)
|
||||
splash->setInfoText(tr("SetupScriptEditor"));
|
||||
m_scriptDialog = new ScriptingDialog(this);
|
||||
m_scriptDialog->initConsole();
|
||||
|
||||
// load the model
|
||||
Q_ASSERT(m_scriptConsole && m_scriptConsole->machine());
|
||||
m_varshowtable->setModel(m_scriptConsole->consoleMachine()->model());
|
||||
}
|
||||
|
||||
// connect settings signals
|
||||
connect(&set, &SettingManager::sigEditorfontSizeChanged, this,
|
||||
|
@ -176,42 +202,37 @@ MainWindow::MainWindow(QWidget *parent) : FramelessMainWindow(parent) {
|
|||
[this](int v) { _decstrlim = v; });
|
||||
|
||||
// ok, build up the dialog of setting
|
||||
if (splash)
|
||||
splash->setInfoText(tr("SetupSetDialog"));
|
||||
buildUpSettingDialog();
|
||||
|
||||
// we start to installing plugin widgets
|
||||
if (splash)
|
||||
splash->setInfoText(tr("SetupPlgWidgets"));
|
||||
installPluginEditorWidgets();
|
||||
auto plgview = m_toolBtneditors.value(PLUGIN_VIEWS);
|
||||
plgview->setEnabled(!plgview->menu()->isEmpty());
|
||||
|
||||
// load saved docking layout
|
||||
if (splash)
|
||||
splash->setInfoText(tr("SetupDockingLayout"));
|
||||
m_dock->restoreState(set.dockLayout());
|
||||
|
||||
m_lastusedpath = set.lastUsedPath();
|
||||
|
||||
if (splash)
|
||||
splash->setInfoText(tr("SetupWaiting"));
|
||||
// others
|
||||
_showtxt = new ShowTextDialog(this);
|
||||
qApp->processEvents();
|
||||
|
||||
// update status
|
||||
updateEditModeEnabled();
|
||||
|
||||
this->setUpdatesEnabled(true);
|
||||
|
||||
// Don't call without QTimer::singleShot.
|
||||
// I don't know why it doesn't work with direct call.
|
||||
QTimer::singleShot(0, this, [this] {
|
||||
auto &set = SettingManager::instance();
|
||||
switch (set.defaultWinState()) {
|
||||
case Qt::WindowNoState:
|
||||
break;
|
||||
case Qt::WindowMinimized:
|
||||
this->showMinimized();
|
||||
break;
|
||||
case Qt::WindowActive:
|
||||
case Qt::WindowMaximized:
|
||||
this->showMaximized();
|
||||
break;
|
||||
case Qt::WindowFullScreen:
|
||||
this->showFullScreen();
|
||||
break;
|
||||
}
|
||||
});
|
||||
if (splash)
|
||||
splash->setInfoText(tr("SetupFinished"));
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow() { Logger::instance().disconnect(); }
|
||||
|
@ -225,17 +246,32 @@ void MainWindow::buildUpRibbonBar() {
|
|||
RibbonCatagories catagories;
|
||||
|
||||
m_ribbonMaps[catagories.FILE] = buildFilePage(m_ribbon->addTab(tr("File")));
|
||||
qApp->processEvents();
|
||||
m_editStateWidgets << (m_ribbonMaps[catagories.EDIT] =
|
||||
buildEditPage(m_ribbon->addTab(tr("Edit"))));
|
||||
qApp->processEvents();
|
||||
m_ribbonMaps[catagories.VIEW] = buildViewPage(m_ribbon->addTab(tr("View")));
|
||||
m_ribbonMaps[catagories.SCRIPT] =
|
||||
buildScriptPage(m_ribbon->addTab(tr("Script")));
|
||||
m_ribbonMaps[catagories.PLUGIN] =
|
||||
buildPluginPage(m_ribbon->addTab(tr("Plugin")));
|
||||
qApp->processEvents();
|
||||
|
||||
auto &set = SettingManager::instance();
|
||||
if (set.scriptEnabled()) {
|
||||
m_ribbonMaps[catagories.SCRIPT] =
|
||||
buildScriptPage(m_ribbon->addTab(tr("Script")));
|
||||
qApp->processEvents();
|
||||
}
|
||||
|
||||
if (set.enablePlugin()) {
|
||||
m_ribbonMaps[catagories.PLUGIN] =
|
||||
buildPluginPage(m_ribbon->addTab(tr("Plugin")));
|
||||
qApp->processEvents();
|
||||
}
|
||||
|
||||
m_ribbonMaps[catagories.SETTING] =
|
||||
buildSettingPage(m_ribbon->addTab(tr("Setting")));
|
||||
qApp->processEvents();
|
||||
m_ribbonMaps[catagories.ABOUT] =
|
||||
buildAboutPage(m_ribbon->addTab(tr("About")));
|
||||
qApp->processEvents();
|
||||
|
||||
connect(m_ribbon, &Ribbon::onDragDropFiles, this,
|
||||
[=](const QStringList &files) {
|
||||
|
@ -262,6 +298,8 @@ void MainWindow::buildUpDockSystem(QWidget *container) {
|
|||
|
||||
CDockManager::setAutoHideConfigFlags(CDockManager::DefaultAutoHideConfig);
|
||||
|
||||
qApp->processEvents();
|
||||
|
||||
m_dock = new CDockManager;
|
||||
m_dock->setStyleSheet(QString());
|
||||
m_dock->setParent(this);
|
||||
|
@ -283,6 +321,8 @@ void MainWindow::buildUpDockSystem(QWidget *container) {
|
|||
updateEditModeEnabled();
|
||||
});
|
||||
|
||||
qApp->processEvents();
|
||||
|
||||
// add empty area
|
||||
auto label = new QLabel(this);
|
||||
|
||||
|
@ -298,6 +338,9 @@ void MainWindow::buildUpDockSystem(QWidget *container) {
|
|||
|
||||
label->setPicture(backimg);
|
||||
label->setAlignment(Qt::AlignCenter);
|
||||
|
||||
qApp->processEvents();
|
||||
|
||||
CDockWidget *CentralDockWidget =
|
||||
new CDockWidget(QStringLiteral("CentralWidget"));
|
||||
CentralDockWidget->setWidget(label);
|
||||
|
@ -305,10 +348,14 @@ void MainWindow::buildUpDockSystem(QWidget *container) {
|
|||
CentralDockWidget->setFeature(ads::CDockWidget::NoTab, true);
|
||||
auto editorViewArea = m_dock->setCentralWidget(CentralDockWidget);
|
||||
|
||||
qApp->processEvents();
|
||||
|
||||
// build up basic docking widgets
|
||||
auto bottomLeftArea =
|
||||
buildUpFindResultDock(m_dock, ads::BottomDockWidgetArea);
|
||||
|
||||
qApp->processEvents();
|
||||
|
||||
auto splitter =
|
||||
ads::internal::findParent<ads::CDockSplitter *>(editorViewArea);
|
||||
if (splitter) {
|
||||
|
@ -316,9 +363,13 @@ void MainWindow::buildUpDockSystem(QWidget *container) {
|
|||
splitter->setSizes({height() - bottomHeight, bottomHeight});
|
||||
}
|
||||
|
||||
qApp->processEvents();
|
||||
|
||||
auto rightArea =
|
||||
buildUpLogDock(m_dock, ads::RightDockWidgetArea, editorViewArea);
|
||||
|
||||
qApp->processEvents();
|
||||
|
||||
splitter = ads::internal::findParent<ads::CDockSplitter *>(editorViewArea);
|
||||
if (splitter) {
|
||||
constexpr auto rightHeight = 450;
|
||||
|
@ -327,21 +378,43 @@ void MainWindow::buildUpDockSystem(QWidget *container) {
|
|||
|
||||
m_rightViewArea = rightArea;
|
||||
|
||||
qApp->processEvents();
|
||||
|
||||
buildUpNumberShowDock(m_dock, ads::CenterDockWidgetArea, rightArea);
|
||||
qApp->processEvents();
|
||||
buildUpHexBookMarkDock(m_dock, ads::CenterDockWidgetArea, rightArea);
|
||||
qApp->processEvents();
|
||||
buildUpHexMetaDataDock(m_dock, ads::CenterDockWidgetArea, rightArea);
|
||||
qApp->processEvents();
|
||||
buildUpDecodingStrShowDock(m_dock, ads::CenterDockWidgetArea, rightArea);
|
||||
auto bottomRightArea = buildUpScriptConsoleDock(
|
||||
m_dock, ads::RightDockWidgetArea, bottomLeftArea);
|
||||
buildUpHashResultDock(m_dock, ads::CenterDockWidgetArea, bottomRightArea);
|
||||
qApp->processEvents();
|
||||
|
||||
ads::CDockAreaWidget *bottomRightArea;
|
||||
if (SettingManager::instance().scriptEnabled()) {
|
||||
bottomRightArea = buildUpScriptConsoleDock(
|
||||
m_dock, ads::RightDockWidgetArea, bottomLeftArea);
|
||||
qApp->processEvents();
|
||||
buildUpScriptObjShowDock(m_dock, ads::CenterDockWidgetArea,
|
||||
bottomRightArea);
|
||||
qApp->processEvents();
|
||||
buildUpHashResultDock(m_dock, ads::CenterDockWidgetArea,
|
||||
bottomRightArea);
|
||||
qApp->processEvents();
|
||||
} else {
|
||||
bottomRightArea = buildUpHashResultDock(
|
||||
m_dock, ads::RightDockWidgetArea, bottomLeftArea);
|
||||
qApp->processEvents();
|
||||
}
|
||||
|
||||
buildUpVisualDataDock(m_dock, ads::CenterDockWidgetArea, bottomLeftArea);
|
||||
buildUpScriptObjShowDock(m_dock, ads::CenterDockWidgetArea,
|
||||
bottomRightArea);
|
||||
qApp->processEvents();
|
||||
|
||||
m_bottomViewArea = bottomRightArea;
|
||||
|
||||
// set the first tab visible
|
||||
for (auto &item : m_dock->openedDockAreas()) {
|
||||
for (int i = 0; i < item->dockWidgetsCount(); ++i) {
|
||||
qApp->processEvents();
|
||||
auto d = item->dockWidget(i);
|
||||
if (d->features().testFlag(ads::CDockWidget::NoTab)) {
|
||||
continue;
|
||||
|
@ -349,6 +422,7 @@ void MainWindow::buildUpDockSystem(QWidget *container) {
|
|||
item->setCurrentIndex(i);
|
||||
break;
|
||||
}
|
||||
qApp->processEvents();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -856,6 +930,7 @@ RibbonTabContent *MainWindow::buildViewPage(RibbonTabContent *tab) {
|
|||
auto shortcuts = QKeySequences::instance();
|
||||
{
|
||||
auto pannel = tab->addGroup(tr("Display"));
|
||||
|
||||
auto menu = new QMenu(this);
|
||||
menu->addAction(newAction(QStringLiteral("80%"), [this] {
|
||||
this->setCurrentHexEditorScale(0.8);
|
||||
|
@ -886,6 +961,8 @@ RibbonTabContent *MainWindow::buildViewPage(RibbonTabContent *tab) {
|
|||
EMPTY_FUNC, {}, menu);
|
||||
addPannelAction(pannel, QStringLiteral("scalereset"), tr("ResetScale"),
|
||||
[this] { this->setCurrentHexEditorScale(1.0); });
|
||||
addPannelAction(pannel, QStringLiteral("viewtxt"), tr("ViewText"),
|
||||
&MainWindow::on_viewtxt);
|
||||
m_editStateWidgets << pannel;
|
||||
}
|
||||
|
||||
|
@ -949,25 +1026,15 @@ RibbonTabContent *MainWindow::buildViewPage(RibbonTabContent *tab) {
|
|||
auto hexeditor = editor->hexEditor();
|
||||
auto doc = hexeditor->document();
|
||||
|
||||
if (hexeditor->isKeepSize() &&
|
||||
(doc->metadata()->hasMetadata() ||
|
||||
doc->bookMarksCount() > 0)) {
|
||||
auto ret = WingMessageBox::warning(
|
||||
this, qAppName(), tr("MetaBrokingPos"),
|
||||
QMessageBox::Yes | QMessageBox::No);
|
||||
if (ret == QMessageBox::No) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto b = !hexeditor->isKeepSize();
|
||||
if ((!b && editor->documentType() ==
|
||||
EditorView::DocumentType::RegionFile) ||
|
||||
!hexeditor->setKeepSize(b)) {
|
||||
Toast::toast(this, _pixCannotOver, tr("ErrUnOver"));
|
||||
} else {
|
||||
if (hexeditor->document()->metadata()->hasMetadata()) {
|
||||
Toast::toast(this, _pixCanOver, tr("InfoCanOverLimit"));
|
||||
if (b) {
|
||||
Toast::toast(this, _pixCannotOver,
|
||||
tr("InfoCanOverLimit"));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1121,15 +1188,24 @@ RibbonTabContent *MainWindow::buildPluginPage(RibbonTabContent *tab) {
|
|||
|
||||
RibbonTabContent *MainWindow::buildSettingPage(RibbonTabContent *tab) {
|
||||
auto shortcuts = QKeySequences::instance();
|
||||
|
||||
auto &set = SettingManager::instance();
|
||||
|
||||
{
|
||||
auto pannel = tab->addGroup(tr("General"));
|
||||
addPannelAction(
|
||||
pannel, QStringLiteral("general"), tr("General"),
|
||||
&MainWindow::on_setting_general,
|
||||
shortcuts.keySequence(QKeySequences::Key::SETTING_GENERAL));
|
||||
|
||||
if (set.scriptEnabled()) {
|
||||
addPannelAction(pannel, QStringLiteral("scriptset"),
|
||||
tr("ScriptSetting"),
|
||||
&MainWindow::on_setting_script);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if (set.enablePlugin()) {
|
||||
auto pannel = tab->addGroup(tr("PluginSettings"));
|
||||
pannel->setVisible(false);
|
||||
connect(pannel, &RibbonButtonGroup::emptyStatusChanged, this,
|
||||
|
@ -1162,6 +1238,8 @@ void MainWindow::buildUpSettingDialog() {
|
|||
QString id;
|
||||
|
||||
m_setdialog = new SettingDialog(this);
|
||||
qApp->processEvents();
|
||||
|
||||
auto generalPage = new GeneralSettingDialog(m_setdialog);
|
||||
connect(generalPage, &SettingPage::optionNeedRestartChanged, m_setdialog,
|
||||
&SettingDialog::toastTakeEffectReboot);
|
||||
|
@ -1170,6 +1248,7 @@ void MainWindow::buildUpSettingDialog() {
|
|||
Q_ASSERT(!id.isEmpty());
|
||||
Q_ASSERT(usedIDs.indexOf(id) < 0);
|
||||
usedIDs.append(id);
|
||||
qApp->processEvents();
|
||||
|
||||
auto editorPage = new EditorSettingDialog(m_setdialog);
|
||||
connect(editorPage, &SettingPage::optionNeedRestartChanged, m_setdialog,
|
||||
|
@ -1179,6 +1258,7 @@ void MainWindow::buildUpSettingDialog() {
|
|||
Q_ASSERT(!id.isEmpty());
|
||||
Q_ASSERT(usedIDs.indexOf(id) < 0);
|
||||
usedIDs.append(id);
|
||||
qApp->processEvents();
|
||||
|
||||
auto plgPage = new PluginSettingDialog(m_setdialog);
|
||||
connect(plgPage, &SettingPage::optionNeedRestartChanged, m_setdialog,
|
||||
|
@ -1189,6 +1269,7 @@ void MainWindow::buildUpSettingDialog() {
|
|||
Q_ASSERT(!id.isEmpty());
|
||||
Q_ASSERT(usedIDs.indexOf(id) < 0);
|
||||
usedIDs.append(id);
|
||||
qApp->processEvents();
|
||||
|
||||
auto scriptPage = new ScriptSettingDialog(m_setdialog);
|
||||
connect(scriptPage, &SettingPage::optionNeedRestartChanged, m_setdialog,
|
||||
|
@ -1198,12 +1279,14 @@ void MainWindow::buildUpSettingDialog() {
|
|||
Q_ASSERT(!id.isEmpty());
|
||||
Q_ASSERT(usedIDs.indexOf(id) < 0);
|
||||
usedIDs.append(id);
|
||||
qApp->processEvents();
|
||||
|
||||
auto otherPage = new OtherSettingsDialog(m_setdialog);
|
||||
id = otherPage->id();
|
||||
Q_ASSERT(!id.isEmpty());
|
||||
Q_ASSERT(usedIDs.indexOf(id) < 0);
|
||||
usedIDs.append(id);
|
||||
qApp->processEvents();
|
||||
|
||||
for (auto page_p = m_settingPages.constKeyValueBegin();
|
||||
page_p != m_settingPages.constKeyValueEnd(); ++page_p) {
|
||||
|
@ -1239,11 +1322,13 @@ void MainWindow::buildUpSettingDialog() {
|
|||
[=] { m_setdialog->showConfig(id); });
|
||||
}
|
||||
usedIDs.append(id);
|
||||
qApp->processEvents();
|
||||
}
|
||||
|
||||
connect(otherPage, &SettingPage::optionNeedRestartChanged, m_setdialog,
|
||||
&SettingDialog::toastTakeEffectReboot);
|
||||
m_setdialog->addPage(otherPage);
|
||||
qApp->processEvents();
|
||||
|
||||
m_setdialog->build();
|
||||
}
|
||||
|
@ -1256,6 +1341,7 @@ void MainWindow::installPluginEditorWidgets() {
|
|||
for (auto p = m_editorViewWidgets.begin(); p != m_editorViewWidgets.end();
|
||||
++p) {
|
||||
for (auto &w : p.value()) {
|
||||
qApp->processEvents();
|
||||
if (names.contains(w->id())) {
|
||||
log.critical(tr("Plugin %1 contains a duplicate ID (%2) that "
|
||||
"is already registered by plugin %3")
|
||||
|
@ -1275,6 +1361,7 @@ void MainWindow::installPluginEditorWidgets() {
|
|||
names.insert(w->id(), p.key());
|
||||
m_editorViewWidgetsBuffer.append(w);
|
||||
}
|
||||
qApp->processEvents();
|
||||
}
|
||||
|
||||
// clear for no using
|
||||
|
@ -1835,13 +1922,8 @@ void MainWindow::on_bookmark() {
|
|||
return;
|
||||
}
|
||||
auto doc = hexeditor->document();
|
||||
if (!doc->isKeepSize()) {
|
||||
Toast::toast(this, NAMEICONRES(QStringLiteral("bookmark")),
|
||||
tr("CheckKeepSize"));
|
||||
return;
|
||||
}
|
||||
|
||||
auto pos = hexeditor->currentOffset();
|
||||
|
||||
if (doc->existBookMark(pos)) {
|
||||
auto bcomment = doc->bookMark(pos);
|
||||
bool ok;
|
||||
|
@ -1869,12 +1951,6 @@ void MainWindow::on_bookmarkdel() {
|
|||
return;
|
||||
}
|
||||
auto doc = hexeditor->document();
|
||||
if (!doc->isKeepSize()) {
|
||||
Toast::toast(this, NAMEICONRES(QStringLiteral("bookmarkdel")),
|
||||
tr("CheckKeepSize"));
|
||||
return;
|
||||
}
|
||||
|
||||
auto pos = hexeditor->currentOffset();
|
||||
|
||||
if (doc->bookMarkExists(pos)) {
|
||||
|
@ -1888,11 +1964,6 @@ void MainWindow::on_bookmarkcls() {
|
|||
return;
|
||||
}
|
||||
auto doc = hexeditor->document();
|
||||
if (!doc->isKeepSize()) {
|
||||
Toast::toast(this, NAMEICONRES(QStringLiteral("bookmarkcls")),
|
||||
tr("CheckKeepSize"));
|
||||
return;
|
||||
}
|
||||
doc->ClearBookMark();
|
||||
}
|
||||
|
||||
|
@ -1902,11 +1973,6 @@ void MainWindow::on_metadata() {
|
|||
return;
|
||||
}
|
||||
auto doc = hexeditor->document();
|
||||
if (!doc->isKeepSize()) {
|
||||
Toast::toast(this, NAMEICONRES(QStringLiteral("metadata")),
|
||||
tr("CheckKeepSize"));
|
||||
return;
|
||||
}
|
||||
if (hexeditor->documentBytes() > 0) {
|
||||
MetaDialog m(this);
|
||||
auto cur = hexeditor->cursor();
|
||||
|
@ -1930,11 +1996,7 @@ void MainWindow::on_metadataedit() {
|
|||
return;
|
||||
}
|
||||
auto doc = hexeditor->document();
|
||||
if (!doc->isKeepSize()) {
|
||||
Toast::toast(this, NAMEICONRES(QStringLiteral("metadataedit")),
|
||||
tr("CheckKeepSize"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (hexeditor->documentBytes() > 0) {
|
||||
MetaDialog m(this);
|
||||
auto cur = hexeditor->cursor();
|
||||
|
@ -1975,11 +2037,6 @@ void MainWindow::on_metadatadel() {
|
|||
return;
|
||||
}
|
||||
auto doc = hexeditor->document();
|
||||
if (!doc->isKeepSize()) {
|
||||
Toast::toast(this, NAMEICONRES(QStringLiteral("metadatadel")),
|
||||
tr("CheckKeepSize"));
|
||||
return;
|
||||
}
|
||||
auto meta = doc->metadata();
|
||||
auto pos = hexeditor->cursor()->position().offset();
|
||||
meta->RemoveMetadata(pos);
|
||||
|
@ -1991,11 +2048,6 @@ void MainWindow::on_metadatacls() {
|
|||
return;
|
||||
}
|
||||
auto doc = hexeditor->document();
|
||||
if (!doc->isKeepSize()) {
|
||||
Toast::toast(this, NAMEICONRES(QStringLiteral("metadatacls")),
|
||||
tr("CheckKeepSize"));
|
||||
return;
|
||||
}
|
||||
doc->metadata()->Clear();
|
||||
}
|
||||
|
||||
|
@ -2239,6 +2291,14 @@ void MainWindow::on_locChanged() {
|
|||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_viewtxt() {
|
||||
auto hexeditor = currentHexView();
|
||||
if (hexeditor == nullptr) {
|
||||
return;
|
||||
}
|
||||
_showtxt->load(hexeditor->document()->buffer());
|
||||
}
|
||||
|
||||
void MainWindow::on_fullScreen() {
|
||||
if (this->isFullScreen()) {
|
||||
this->showMaximized();
|
||||
|
@ -2275,6 +2335,10 @@ void MainWindow::on_scriptwindow() {
|
|||
|
||||
void MainWindow::on_setting_general() { m_setdialog->showConfig(); }
|
||||
|
||||
void MainWindow::on_setting_script() {
|
||||
m_scriptDialog->settingDialog()->showConfig();
|
||||
}
|
||||
|
||||
void MainWindow::on_setting_plugin() { m_setdialog->showConfig(2); }
|
||||
|
||||
void MainWindow::on_about() { AboutSoftwareDialog().exec(); }
|
||||
|
@ -2401,11 +2465,6 @@ void MainWindow::connectEditorView(EditorView *editor) {
|
|||
return;
|
||||
}
|
||||
auto doc = hexeditor->document();
|
||||
if (!doc->isKeepSize()) {
|
||||
Toast::toast(this, NAMEICONRES(QStringLiteral("metadataedit")),
|
||||
tr("CheckKeepSize"));
|
||||
return;
|
||||
}
|
||||
if (hexeditor->documentBytes() > 0) {
|
||||
MetaDialog m(this);
|
||||
auto cur = hexeditor->cursor();
|
||||
|
@ -2939,5 +2998,7 @@ void MainWindow::closeEvent(QCloseEvent *event) {
|
|||
set.setRecentFiles(m_recentmanager->saveRecent());
|
||||
set.save();
|
||||
|
||||
LangService::instance().saveSnippets();
|
||||
|
||||
FramelessMainWindow::closeEvent(event);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include "dialog/splashdialog.h"
|
||||
#include "framelessmainwindow.h"
|
||||
|
||||
#include <QListView>
|
||||
|
@ -50,6 +51,7 @@
|
|||
#include "plugin/iwingplugin.h"
|
||||
#include "scriptingdialog.h"
|
||||
#include "settingdialog.h"
|
||||
#include "showtextdialog.h"
|
||||
#include "utilities.h"
|
||||
|
||||
class PluginSystem;
|
||||
|
@ -60,7 +62,7 @@ class MainWindow : public FramelessMainWindow {
|
|||
friend class PluginSystem;
|
||||
|
||||
public:
|
||||
MainWindow(QWidget *parent = nullptr);
|
||||
explicit MainWindow(SplashDialog *splash);
|
||||
virtual ~MainWindow() override;
|
||||
|
||||
private:
|
||||
|
@ -183,6 +185,7 @@ private slots:
|
|||
void on_exportfindresult();
|
||||
void on_locChanged();
|
||||
|
||||
void on_viewtxt();
|
||||
void on_fullScreen();
|
||||
void on_restoreLayout();
|
||||
void on_exportlog();
|
||||
|
@ -190,6 +193,7 @@ private slots:
|
|||
|
||||
void on_scriptwindow();
|
||||
void on_setting_general();
|
||||
void on_setting_script();
|
||||
void on_setting_plugin();
|
||||
|
||||
void on_about();
|
||||
|
@ -383,19 +387,17 @@ private:
|
|||
watcher->setFuture(fu);
|
||||
|
||||
if (!tip.isEmpty()) {
|
||||
std::unique_ptr<WingProgressDialog> pdialog(
|
||||
new WingProgressDialog(tip, QString(), 0, 0));
|
||||
auto dialog = pdialog->dialog();
|
||||
dialog->setModal(true);
|
||||
dialog->setValue(0);
|
||||
auto pdialog = new WingProgressDialog(tip, QString(), 0, 0);
|
||||
pdialog->setModal(true);
|
||||
pdialog->setValue(0);
|
||||
|
||||
QObject::connect(watcher, &QFutureWatcher<ReturnType>::finished,
|
||||
this, [dialog]() mutable {
|
||||
dialog->cancel();
|
||||
dialog->deleteLater();
|
||||
this, [pdialog]() mutable {
|
||||
pdialog->cancel();
|
||||
pdialog->deleteLater();
|
||||
});
|
||||
|
||||
pdialog->pdialog()->exec();
|
||||
pdialog->exec();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -414,19 +416,17 @@ private:
|
|||
watcher->setFuture(fu);
|
||||
|
||||
if (!tip.isEmpty()) {
|
||||
std::unique_ptr<WingProgressDialog> pdialog(
|
||||
new WingProgressDialog(tip, QString(), 0, 0));
|
||||
auto dialog = pdialog->dialog();
|
||||
dialog->setModal(true);
|
||||
dialog->setValue(0);
|
||||
auto pdialog = new WingProgressDialog(tip, QString(), 0, 0);
|
||||
pdialog->setModal(true);
|
||||
pdialog->setValue(0);
|
||||
|
||||
QObject::connect(watcher, &QFutureWatcher<void>::finished, this,
|
||||
[dialog]() mutable {
|
||||
dialog->cancel();
|
||||
dialog->deleteLater();
|
||||
[pdialog]() mutable {
|
||||
pdialog->cancel();
|
||||
pdialog->deleteLater();
|
||||
});
|
||||
|
||||
pdialog->pdialog()->exec();
|
||||
pdialog->exec();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -542,5 +542,7 @@ private:
|
|||
bool m_islittle = true;
|
||||
bool m_enablePlugin = true;
|
||||
bool m_isOnClosing = false;
|
||||
|
||||
ShowTextDialog *_showtxt = nullptr;
|
||||
};
|
||||
#endif // MAINWINDOW_H
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include "QWingRibbon/ribbontabcontent.h"
|
||||
#include "Qt-Advanced-Docking-System/src/DockAreaWidget.h"
|
||||
#include "aboutsoftwaredialog.h"
|
||||
#include "class/clangformatmanager.h"
|
||||
#include "class/langservice.h"
|
||||
#include "class/languagemanager.h"
|
||||
#include "class/qkeysequences.h"
|
||||
|
@ -28,8 +27,8 @@
|
|||
#include "class/wingfiledialog.h"
|
||||
#include "class/wingmessagebox.h"
|
||||
#include "control/toast.h"
|
||||
#include "qcodeeditwidget/qdocumentswaptextcommand.h"
|
||||
#include "qcodeeditwidget/qeditconfig.h"
|
||||
#include "qcodeeditwidget/qformatconfig.h"
|
||||
#include "qcodeeditwidget/qsnippetedit.h"
|
||||
#include "qdocumentline.h"
|
||||
#include "qeditor.h"
|
||||
|
@ -81,9 +80,6 @@ ScriptingDialog::ScriptingDialog(QWidget *parent)
|
|||
|
||||
buildUpSettingDialog();
|
||||
|
||||
QFormatScheme *format = QDocument::defaultFormatScheme();
|
||||
Q_ASSERT(format);
|
||||
|
||||
auto lmic = QLineMarksInfoCenter::instance();
|
||||
lmic->loadMarkTypes(QCE::fetchDataFile(":/qcodeedit/marks.qxm"));
|
||||
// get symbol ID
|
||||
|
@ -113,6 +109,11 @@ ScriptingDialog::~ScriptingDialog() {}
|
|||
|
||||
void ScriptingDialog::initConsole() {
|
||||
Q_ASSERT(m_consoleout);
|
||||
|
||||
auto fmt = new QFormatScheme(this);
|
||||
LangService::addAdditionalFormat(fmt);
|
||||
m_consoleout->document()->setFormatScheme(fmt);
|
||||
|
||||
m_consoleout->init();
|
||||
auto machine = m_consoleout->machine();
|
||||
connect(machine, &ScriptMachine::onDebugFinished, this, [=] {
|
||||
|
@ -217,6 +218,8 @@ void ScriptingDialog::initConsole() {
|
|||
|
||||
updateRunDebugMode();
|
||||
});
|
||||
|
||||
m_sym->setEngine(machine->engine());
|
||||
}
|
||||
|
||||
bool ScriptingDialog::about2Close() {
|
||||
|
@ -287,7 +290,19 @@ void ScriptingDialog::buildUpRibbonBar() {
|
|||
connect(m_ribbon, &Ribbon::onDragDropFiles, this,
|
||||
[=](const QStringList &files) {
|
||||
for (auto &file : files) {
|
||||
openFile(file);
|
||||
QFileInfo info(file);
|
||||
auto suffix = info.suffix();
|
||||
if (info.exists() && Utilities::isTextFile(info) &&
|
||||
(suffix.compare(QStringLiteral("as"),
|
||||
Qt::CaseInsensitive) == 0 ||
|
||||
suffix.compare(QStringLiteral("anglescript"),
|
||||
Qt::CaseInsensitive) == 0)) {
|
||||
openFile(file);
|
||||
} else {
|
||||
Toast::toast(this,
|
||||
NAMEICONRES(QStringLiteral("script")),
|
||||
tr("InvalidSourceFile"));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -524,6 +539,8 @@ RibbonTabContent *ScriptingDialog::buildSettingPage(RibbonTabContent *tab) {
|
|||
addPannelAction(
|
||||
pannel, QStringLiteral("codeformat"), tr("ClangFormat"),
|
||||
[=] { m_setdialog->showConfig(QStringLiteral("ClangFormat")); });
|
||||
addPannelAction(pannel, QStringLiteral("scheme"), tr("Format"),
|
||||
[=] { m_setdialog->showConfig(QStringLiteral("Scheme")); });
|
||||
return tab;
|
||||
}
|
||||
|
||||
|
@ -607,16 +624,13 @@ ScriptingDialog::buildUpStackShowDock(ads::CDockManager *dock,
|
|||
}
|
||||
|
||||
ads::CDockAreaWidget *
|
||||
ScriptingDialog::buildUpWatchDock(ads::CDockManager *dock,
|
||||
ads::DockWidgetArea area,
|
||||
ads::CDockAreaWidget *areaw) {
|
||||
auto watch = new QTableView(this);
|
||||
Utilities::applyTableViewProperty(watch);
|
||||
m_watch = new DbgVarShowModel(watch);
|
||||
watch->setModel(m_watch);
|
||||
|
||||
ScriptingDialog::buildSymbolShowDock(ads::CDockManager *dock,
|
||||
ads::DockWidgetArea area,
|
||||
ads::CDockAreaWidget *areaw) {
|
||||
Q_ASSERT(m_consoleout);
|
||||
m_sym = new ASObjTreeWidget(this);
|
||||
auto dw =
|
||||
buildDockWidget(dock, QStringLiteral("Watch"), tr("Watch"), watch);
|
||||
buildDockWidget(dock, QStringLiteral("Symbol"), tr("Symbol"), m_sym);
|
||||
return dock->addDockWidget(area, dw, areaw);
|
||||
}
|
||||
|
||||
|
@ -685,9 +699,7 @@ void ScriptingDialog::buildUpDockSystem(QWidget *container) {
|
|||
auto rightArea = buildUpBreakpointShowDock(m_dock, ads::RightDockWidgetArea,
|
||||
m_editorViewArea);
|
||||
buildUpVarShowDock(m_dock, ads::CenterDockWidgetArea, rightArea);
|
||||
|
||||
// not avaliable for v1.0.0
|
||||
// buildUpWatchDock(m_dock, ads::CenterDockWidgetArea, rightArea);
|
||||
buildSymbolShowDock(m_dock, ads::CenterDockWidgetArea, rightArea);
|
||||
|
||||
// set the first tab visible
|
||||
for (auto &item : m_dock->openedDockAreas()) {
|
||||
|
@ -963,12 +975,17 @@ void ScriptingDialog::buildUpSettingDialog() {
|
|||
auto edit = new QEditConfig(m_setdialog);
|
||||
m_setdialog->addPage(edit);
|
||||
|
||||
auto clang = new ClangFormatSetDialog(m_setdialog);
|
||||
m_setdialog->addPage(clang);
|
||||
|
||||
auto snip =
|
||||
new QSnippetEdit(LangService::instance().snippetManager(), m_setdialog);
|
||||
m_setdialog->addPage(snip);
|
||||
|
||||
auto clang = new ClangFormatSetDialog(m_setdialog);
|
||||
m_setdialog->addPage(clang);
|
||||
auto &langsev = LangService::instance();
|
||||
auto scheme = new QFormatConfig(langsev.formatSchemes(),
|
||||
langsev.defaultSchemeName(), m_setdialog);
|
||||
m_setdialog->addPage(scheme);
|
||||
|
||||
m_setdialog->build();
|
||||
}
|
||||
|
@ -1130,10 +1147,6 @@ void ScriptingDialog::on_openfile() {
|
|||
if (!filename.isEmpty()) {
|
||||
m_lastusedpath = QFileInfo(filename).absoluteDir().absolutePath();
|
||||
openFile(filename);
|
||||
|
||||
// TODO test
|
||||
// QAsParser parser(m_consoleout->machine()->engine());
|
||||
// parser.parse(filename);
|
||||
}
|
||||
|
||||
RecentFileManager::RecentInfo info;
|
||||
|
@ -1258,15 +1271,7 @@ void ScriptingDialog::on_gotoline() {
|
|||
void ScriptingDialog::on_codefmt() {
|
||||
auto e = currentEditor();
|
||||
if (e) {
|
||||
auto editor = e->editor();
|
||||
auto codes = editor->text();
|
||||
bool ok;
|
||||
|
||||
auto fmtcodes = ClangFormatManager::instance().formatCode(codes, ok);
|
||||
if (ok) {
|
||||
auto doc = editor->document();
|
||||
doc->execute(new QDocumentSwapTextCommand(fmtcodes, doc));
|
||||
} else {
|
||||
if (!e->formatCode()) {
|
||||
Toast::toast(this, NAMEICONRES(QStringLiteral("codefmt")),
|
||||
tr("FormatCodeFailed"));
|
||||
}
|
||||
|
@ -1300,7 +1305,13 @@ void ScriptingDialog::on_wiki() {
|
|||
"doc_script.html")));
|
||||
}
|
||||
|
||||
void ScriptingDialog::on_fullScreen() { this->showFullScreen(); }
|
||||
void ScriptingDialog::on_fullScreen() {
|
||||
if (this->isFullScreen()) {
|
||||
this->showMaximized();
|
||||
} else {
|
||||
this->showFullScreen();
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptingDialog::on_restoreLayout() {
|
||||
m_dock->restoreState(_defaultLayout);
|
||||
|
@ -1403,3 +1414,5 @@ void ScriptingDialog::closeEvent(QCloseEvent *event) {
|
|||
|
||||
FramelessMainWindow::closeEvent(event);
|
||||
}
|
||||
|
||||
SettingDialog *ScriptingDialog::settingDialog() const { return m_setdialog; }
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#ifndef SCRIPTINGDIALOG_H
|
||||
#define SCRIPTINGDIALOG_H
|
||||
|
||||
#include "control/asobjtreewidget.h"
|
||||
#include "control/scriptingconsole.h"
|
||||
#include "dialog/settingdialog.h"
|
||||
#include "framelessmainwindow.h"
|
||||
|
@ -31,7 +32,6 @@
|
|||
#include "model/dbgbreakpointmodel.h"
|
||||
#include "model/dbgcallstackmodel.h"
|
||||
#include "model/dbgvarshowmodel.h"
|
||||
#include "qlanguagefactory.h"
|
||||
#include "utilities.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
|
@ -79,6 +79,8 @@ public:
|
|||
|
||||
void saveDockLayout();
|
||||
|
||||
SettingDialog *settingDialog() const;
|
||||
|
||||
private:
|
||||
void buildUpRibbonBar();
|
||||
RibbonTabContent *buildFilePage(RibbonTabContent *tab);
|
||||
|
@ -101,8 +103,8 @@ private:
|
|||
buildUpStackShowDock(ads::CDockManager *dock, ads::DockWidgetArea area,
|
||||
ads::CDockAreaWidget *areaw = nullptr);
|
||||
ads::CDockAreaWidget *
|
||||
buildUpWatchDock(ads::CDockManager *dock, ads::DockWidgetArea area,
|
||||
ads::CDockAreaWidget *areaw = nullptr);
|
||||
buildSymbolShowDock(ads::CDockManager *dock, ads::DockWidgetArea area,
|
||||
ads::CDockAreaWidget *areaw = nullptr);
|
||||
|
||||
void buildUpDockSystem(QWidget *container);
|
||||
|
||||
|
@ -282,8 +284,8 @@ private:
|
|||
DbgVarShowModel *m_varshow = nullptr;
|
||||
DbgVarShowModel *m_gvarshow = nullptr;
|
||||
DbgBreakpointModel *m_breakpoints = nullptr;
|
||||
DbgVarShowModel *m_watch = nullptr;
|
||||
DbgCallStackModel *m_callstack = nullptr;
|
||||
ASObjTreeWidget *m_sym = nullptr;
|
||||
|
||||
QString _DebugingScript;
|
||||
|
||||
|
|
|
@ -0,0 +1,240 @@
|
|||
/*==============================================================================
|
||||
** 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 "showtextdialog.h"
|
||||
|
||||
#include "class/qkeysequences.h"
|
||||
#include "class/wingmessagebox.h"
|
||||
#include "class/wingprogressdialog.h"
|
||||
#include "control/codeedit.h"
|
||||
#include "dialog/encodingdialog.h"
|
||||
#include "qeditor.h"
|
||||
|
||||
#include <QThread>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
constexpr auto EMPTY_FUNC = [] {};
|
||||
|
||||
ShowTextDialog::ShowTextDialog(QWidget *parent) : FramelessDialogBase(parent) {
|
||||
this->setUpdatesEnabled(false);
|
||||
|
||||
// build up UI
|
||||
buildUpRibbonBar();
|
||||
|
||||
auto cw = new QWidget(this);
|
||||
cw->setSizePolicy(
|
||||
QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
|
||||
auto layout = new QVBoxLayout(cw);
|
||||
layout->setContentsMargins(1, 0, 1, 0);
|
||||
layout->setSpacing(0);
|
||||
layout->addWidget(q_check_ptr(m_ribbon));
|
||||
|
||||
m_edit = new CodeEdit(false, this, false);
|
||||
auto editor = m_edit->editor();
|
||||
editor->setCodec(QStringLiteral("ASCII"));
|
||||
connect(editor, &QEditor::needLoading, this,
|
||||
[this]() { load(m_last.buffer, m_last.offset, m_last.size); });
|
||||
|
||||
editor->setFlag(QEditor::ReadOnly, true);
|
||||
editor->setAcceptDrops(false);
|
||||
editor->setUndoRedoEnabled(false);
|
||||
editor->createSimpleBasicContextMenu(true, true);
|
||||
layout->addWidget(editor);
|
||||
|
||||
m_status = new QStatusBar(this);
|
||||
layout->addWidget(m_status);
|
||||
buildUpContent(cw);
|
||||
|
||||
// ok, preparing for starting...
|
||||
this->setWindowTitle(tr("TextBroswer"));
|
||||
this->setWindowIcon(ICONRES(QStringLiteral("viewtxt")));
|
||||
this->setMinimumSize(800, 600);
|
||||
|
||||
this->setUpdatesEnabled(true);
|
||||
}
|
||||
|
||||
ShowTextDialog::~ShowTextDialog() {}
|
||||
|
||||
void ShowTextDialog::load(QHexBuffer *buffer, const QString encoding,
|
||||
qsizetype offset, qsizetype size) {
|
||||
auto editor = m_edit->editor();
|
||||
editor->blockSignals(true);
|
||||
load(buffer, offset, size);
|
||||
editor->blockSignals(false);
|
||||
}
|
||||
|
||||
void ShowTextDialog::load(QHexBuffer *buffer, qsizetype offset,
|
||||
qsizetype size) {
|
||||
if (buffer == nullptr || offset < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_canceled = false;
|
||||
|
||||
if (size < 0) {
|
||||
size = buffer->length();
|
||||
}
|
||||
|
||||
if (size >= std::numeric_limits<decltype(size)>::max()) {
|
||||
WingMessageBox::critical(this, this->windowTitle(), tr("TooHugeFile"));
|
||||
return;
|
||||
}
|
||||
|
||||
auto editor = m_edit->editor();
|
||||
editor->setUpdatesEnabled(false);
|
||||
|
||||
auto doc = editor->document();
|
||||
auto orign = offset;
|
||||
|
||||
WingProgressDialog pdialog(tr("Loading"), tr("Cancel"), 0, size - orign);
|
||||
pdialog.setAutoClose(false);
|
||||
pdialog.setAutoReset(true);
|
||||
|
||||
connect(&pdialog, &WingProgressDialog::canceled, this,
|
||||
&ShowTextDialog::on_cancel);
|
||||
pdialog.open();
|
||||
|
||||
QEventLoop loop;
|
||||
|
||||
auto th = QThread::create([&] {
|
||||
QByteArray ba;
|
||||
auto codec = editor->codecName();
|
||||
|
||||
doc->startChunkLoading();
|
||||
constexpr auto CHUNK_SIZE = 100000;
|
||||
|
||||
do {
|
||||
ba = buffer->read(offset, CHUNK_SIZE);
|
||||
offset += ba.size();
|
||||
|
||||
if (codec.size())
|
||||
doc->addChunk(QCE::convertString(codec, ba));
|
||||
else
|
||||
doc->addChunk(QString::fromLatin1(ba));
|
||||
|
||||
QMetaObject::invokeMethod(
|
||||
qApp, [&] { pdialog.setValue(offset - orign); });
|
||||
qApp->processEvents();
|
||||
} while (!m_canceled && (offset < size) && ba.size());
|
||||
|
||||
pdialog.setRange(-1, -1);
|
||||
doc->stopChunkLoading();
|
||||
editor->setCursor(QDocumentCursor(doc));
|
||||
pdialog.close();
|
||||
});
|
||||
|
||||
connect(th, &QThread::finished, this,
|
||||
[this, buffer, orign, th, &offset, &loop] {
|
||||
// record
|
||||
m_last.buffer = buffer;
|
||||
m_last.offset = orign;
|
||||
m_last.size = offset;
|
||||
|
||||
show();
|
||||
loop.quit();
|
||||
th->deleteLater();
|
||||
});
|
||||
|
||||
th->start();
|
||||
|
||||
loop.exec();
|
||||
editor->setUpdatesEnabled(true);
|
||||
m_status->showMessage(editor->codecName());
|
||||
}
|
||||
|
||||
void ShowTextDialog::buildUpRibbonBar() {
|
||||
m_ribbon = new Ribbon(this);
|
||||
m_ribbon->setAcceptDrops(false);
|
||||
buildEditPage(m_ribbon->addTab(tr("Edit")));
|
||||
buildViewPage(m_ribbon->addTab(tr("View")));
|
||||
}
|
||||
|
||||
RibbonTabContent *ShowTextDialog::buildEditPage(RibbonTabContent *tab) {
|
||||
auto shortcuts = QKeySequences::instance();
|
||||
{
|
||||
auto pannel = tab->addGroup(tr("General"));
|
||||
|
||||
auto a = addPannelAction(pannel, QStringLiteral("copy"), tr("Copy"),
|
||||
&ShowTextDialog::on_copyfile);
|
||||
setPannelActionToolTip(a, QKeySequence::Copy);
|
||||
|
||||
a = addPannelAction(pannel, QStringLiteral("find"), tr("Find"),
|
||||
&ShowTextDialog::on_findfile);
|
||||
setPannelActionToolTip(a, QKeySequence::Find);
|
||||
|
||||
a = addPannelAction(pannel, QStringLiteral("jmp"), tr("Goto"),
|
||||
&ShowTextDialog::on_gotoline);
|
||||
setPannelActionToolTip(a,
|
||||
shortcuts.keySequence(QKeySequences::Key::GOTO));
|
||||
|
||||
addPannelAction(pannel, QStringLiteral("encoding"), tr("Encoding"),
|
||||
&ShowTextDialog::on_encoding,
|
||||
shortcuts.keySequence(QKeySequences::Key::ENCODING));
|
||||
}
|
||||
|
||||
return tab;
|
||||
}
|
||||
|
||||
RibbonTabContent *ShowTextDialog::buildViewPage(RibbonTabContent *tab) {
|
||||
auto shortcuts = QKeySequences::instance();
|
||||
|
||||
auto pannel = tab->addGroup(tr("Display"));
|
||||
auto menu = new QMenu(this);
|
||||
menu->addAction(newAction(QStringLiteral("80%"),
|
||||
[this] { this->setCurrentEditorScale(0.8); }));
|
||||
menu->addAction(newAction(QStringLiteral("90%"),
|
||||
[this] { this->setCurrentEditorScale(0.9); }));
|
||||
menu->addAction(newAction(QStringLiteral("100%"),
|
||||
[this] { this->setCurrentEditorScale(1.0); }));
|
||||
menu->addSeparator();
|
||||
menu->addAction(newAction(QStringLiteral("120%"),
|
||||
[this] { this->setCurrentEditorScale(1.2); }));
|
||||
menu->addAction(newAction(QStringLiteral("150%"),
|
||||
[this] { this->setCurrentEditorScale(1.5); }));
|
||||
menu->addAction(newAction(QStringLiteral("200%"),
|
||||
[this] { this->setCurrentEditorScale(2.0); }));
|
||||
menu->addAction(newAction(QStringLiteral("250%"),
|
||||
[this] { this->setCurrentEditorScale(2.5); }));
|
||||
menu->addAction(newAction(QStringLiteral("300%"),
|
||||
[this] { this->setCurrentEditorScale(3.0); }));
|
||||
addPannelAction(pannel, QStringLiteral("scale"), tr("Scale"), EMPTY_FUNC,
|
||||
{}, menu);
|
||||
addPannelAction(pannel, QStringLiteral("scalereset"), tr("ResetScale"),
|
||||
[this] { this->setCurrentEditorScale(1.0); });
|
||||
|
||||
return tab;
|
||||
}
|
||||
|
||||
void ShowTextDialog::setCurrentEditorScale(qreal rate) {
|
||||
m_edit->editor()->setScaleRate(rate);
|
||||
}
|
||||
|
||||
void ShowTextDialog::on_copyfile() { m_edit->editor()->copy(); }
|
||||
|
||||
void ShowTextDialog::on_findfile() { m_edit->editor()->find(); }
|
||||
|
||||
void ShowTextDialog::on_gotoline() { m_edit->editor()->gotoLine(); }
|
||||
|
||||
void ShowTextDialog::on_encoding() {
|
||||
EncodingDialog d;
|
||||
if (d.exec()) {
|
||||
auto res = d.getResult();
|
||||
m_edit->editor()->setCodec(res);
|
||||
}
|
||||
}
|
||||
|
||||
void ShowTextDialog::on_cancel() { m_canceled = true; }
|
|
@ -0,0 +1,137 @@
|
|||
/*==============================================================================
|
||||
** 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 SHOWTEXTDIALOG_H
|
||||
#define SHOWTEXTDIALOG_H
|
||||
|
||||
#include "QHexView/document/buffer/qhexbuffer.h"
|
||||
|
||||
#include "QWingRibbon/ribbon.h"
|
||||
#include "QWingRibbon/ribbonbuttongroup.h"
|
||||
#include "QWingRibbon/ribbontabcontent.h"
|
||||
#include "control/codeedit.h"
|
||||
#include "framelessdialogbase.h"
|
||||
#include "utilities.h"
|
||||
|
||||
#include <QShortcut>
|
||||
#include <QStatusBar>
|
||||
#include <QToolButton>
|
||||
|
||||
class ShowTextDialog : public FramelessDialogBase {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ShowTextDialog(QWidget *parent = nullptr);
|
||||
virtual ~ShowTextDialog();
|
||||
|
||||
public:
|
||||
void load(QHexBuffer *buffer, const QString encoding, qsizetype offset = 0,
|
||||
qsizetype size = -1);
|
||||
void load(QHexBuffer *buffer, qsizetype offset = 0, qsizetype size = -1);
|
||||
|
||||
private:
|
||||
void buildUpRibbonBar();
|
||||
|
||||
RibbonTabContent *buildEditPage(RibbonTabContent *tab);
|
||||
RibbonTabContent *buildViewPage(RibbonTabContent *tab);
|
||||
|
||||
void setCurrentEditorScale(qreal rate);
|
||||
|
||||
private:
|
||||
template <typename Func>
|
||||
inline QToolButton *
|
||||
addPannelAction(RibbonButtonGroup *pannel, const QString &iconName,
|
||||
const QString &title, Func &&slot,
|
||||
const QKeySequence &shortcut = QKeySequence(),
|
||||
QMenu *menu = nullptr) {
|
||||
return addPannelAction(pannel, ICONRES(iconName), title, slot, shortcut,
|
||||
menu);
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
inline QToolButton *
|
||||
addPannelAction(RibbonButtonGroup *pannel, const QIcon &icon,
|
||||
const QString &title, Func &&slot,
|
||||
const QKeySequence &shortcut = QKeySequence(),
|
||||
QMenu *menu = nullptr) {
|
||||
Q_ASSERT(pannel);
|
||||
auto a = new QToolButton(pannel);
|
||||
a->setText(title);
|
||||
a->setIcon(icon);
|
||||
setPannelActionToolTip(a, shortcut);
|
||||
|
||||
if (!shortcut.isEmpty()) {
|
||||
auto shortCut = new QShortcut(shortcut, this);
|
||||
shortCut->setContext(Qt::WindowShortcut);
|
||||
connect(shortCut, &QShortcut::activated, a, &QToolButton::click);
|
||||
}
|
||||
|
||||
a->setMenu(menu);
|
||||
if (menu) {
|
||||
a->setPopupMode(QToolButton::InstantPopup);
|
||||
}
|
||||
connect(a, &QToolButton::clicked, this, slot);
|
||||
pannel->addButton(a);
|
||||
return a;
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
inline QAction *newAction(const QString &title, Func &&slot,
|
||||
const QKeySequence &shortcut = QKeySequence()) {
|
||||
auto a = new QAction;
|
||||
a->setText(title);
|
||||
a->setShortcutVisibleInContextMenu(true);
|
||||
a->setShortcut(shortcut);
|
||||
connect(a, &QAction::triggered, this, slot);
|
||||
return a;
|
||||
}
|
||||
|
||||
inline void
|
||||
setPannelActionToolTip(QToolButton *action,
|
||||
const QKeySequence &shortcut = QKeySequence()) {
|
||||
Q_ASSERT(action);
|
||||
auto title = action->text();
|
||||
action->setToolTip(
|
||||
shortcut.isEmpty()
|
||||
? QStringLiteral("<p align=\"center\">%1</p>").arg(title)
|
||||
: QStringLiteral(
|
||||
"<p align=\"center\">%1</p><p align=\"center\">%2</p>")
|
||||
.arg(title, shortcut.toString()));
|
||||
}
|
||||
|
||||
private slots:
|
||||
void on_copyfile();
|
||||
void on_findfile();
|
||||
void on_gotoline();
|
||||
void on_encoding();
|
||||
|
||||
void on_cancel();
|
||||
|
||||
private:
|
||||
Ribbon *m_ribbon = nullptr;
|
||||
CodeEdit *m_edit = nullptr;
|
||||
bool m_canceled = false;
|
||||
|
||||
QStatusBar *m_status = nullptr;
|
||||
|
||||
struct {
|
||||
QHexBuffer *buffer = nullptr;
|
||||
qsizetype offset = 0;
|
||||
qsizetype size = -1;
|
||||
} m_last;
|
||||
};
|
||||
|
||||
#endif // SHOWTEXTDIALOG_H
|
|
@ -0,0 +1,44 @@
|
|||
/*==============================================================================
|
||||
** 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 "splashdialog.h"
|
||||
#include "ui_splashdialog.h"
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
SplashDialog::SplashDialog(QWidget *parent)
|
||||
: QDialog(parent), ui(new Ui::SplashDialog) {
|
||||
ui->setupUi(this);
|
||||
ui->label->setText(
|
||||
QStringLiteral("<html><head/><body><p><span style=\" font-size:16pt; "
|
||||
"font-weight:600;\">%1</span></p></body></html>")
|
||||
.arg(qAppName()));
|
||||
setWindowFlags(Qt::CustomizeWindowHint | Qt::SplashScreen |
|
||||
Qt::WindowStaysOnTopHint);
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
setModal(true);
|
||||
show();
|
||||
}
|
||||
|
||||
SplashDialog::~SplashDialog() { delete ui; }
|
||||
|
||||
void SplashDialog::setInfoText(const QString &text) {
|
||||
ui->lblinfo->setText(text + QStringLiteral("..."));
|
||||
qApp->processEvents();
|
||||
}
|
||||
|
||||
void SplashDialog::cancel() { close(); }
|
|
@ -15,24 +15,28 @@
|
|||
** =============================================================================
|
||||
*/
|
||||
|
||||
#ifndef SCRIPTBEHAVIORSETTINGDIALOG_H
|
||||
#define SCRIPTBEHAVIORSETTINGDIALOG_H
|
||||
#ifndef SPLASHDIALOG_H
|
||||
#define SPLASHDIALOG_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui {
|
||||
class ScriptBehaviorSettingDialog;
|
||||
class SplashDialog;
|
||||
}
|
||||
|
||||
class ScriptBehaviorSettingDialog : public QWidget {
|
||||
class SplashDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ScriptBehaviorSettingDialog(QWidget *parent = nullptr);
|
||||
~ScriptBehaviorSettingDialog();
|
||||
explicit SplashDialog(QWidget *parent = nullptr);
|
||||
virtual ~SplashDialog() override;
|
||||
|
||||
public slots:
|
||||
void setInfoText(const QString &text);
|
||||
void cancel();
|
||||
|
||||
private:
|
||||
Ui::ScriptBehaviorSettingDialog *ui;
|
||||
Ui::SplashDialog *ui;
|
||||
};
|
||||
|
||||
#endif // SCRIPTBEHAVIORSETTINGDIALOG_H
|
||||
#endif // SPLASHDIALOG_H
|
|
@ -0,0 +1,144 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>SplashDialog</class>
|
||||
<widget class="QDialog" name="SplashDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>200</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>15</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>25</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>25</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>25</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>25</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblicon">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>100</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::NoContextMenu</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="../../resources.qrc">:/com.wingsummer.winghex/images/icon.png</pixmap>
|
||||
</property>
|
||||
<property name="scaledContents">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string notr="true"><html><head/><body><p><span style=" font-size:16pt; font-weight:600;">-</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::AutoText</enum>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblinfo">
|
||||
<property name="text">
|
||||
<string notr="true">info</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QProgressBar" name="progressBar">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="textVisible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../../resources.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue