Compare commits

...

7 Commits

122 changed files with 6091 additions and 4183 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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:
/*================================*/

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -57,7 +57,6 @@ public slots:
signals:
void snippetAdded(QSnippet *s);
void snippetRemovedByIndex(int i);
void snippetRemoved(QSnippet *s);

View File

@ -63,6 +63,8 @@ QFoldPanel::~QFoldPanel() {}
*/
QString QFoldPanel::type() const { return "Fold indicators"; }
QString QFoldPanel::name() const { return tr("Fold Panel"); }
/*!
*/

View File

@ -37,6 +37,7 @@ public:
virtual ~QFoldPanel();
virtual QString type() const;
virtual QString name() const;
protected:
virtual void mousePressEvent(QMouseEvent *e);

View File

@ -60,6 +60,8 @@ QLineChangePanel::~QLineChangePanel() {}
*/
QString QLineChangePanel::type() const { return "Line changes"; }
QString QLineChangePanel::name() const { return tr("Line Change Panel"); }
/*!
\internal
*/

View File

@ -40,6 +40,7 @@ public:
virtual ~QLineChangePanel();
virtual QString type() const;
virtual QString name() const;
protected:
virtual void paint(QPainter *p, QEditor *e);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

BIN
images/scheme.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

BIN
images/scriptset.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
images/viewtxt.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@ -1,2 +0,0 @@
* 简体中文寂静的羽夏wingsummer【原生支持】

File diff suppressed because it is too large Load Diff

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 &sectionName,
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 &sectionname,
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 &section,
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;
}

200
src/class/aspreprocesser.h Normal file
View File

@ -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 &sectionName, 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 &sectionname, 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 &section, 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

View File

@ -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 &params,
}
}
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; }

View File

@ -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 &params, const QString &stdinput,
bool &ok);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

48
src/control/codeedit.cpp Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

137
src/dialog/showtextdialog.h Normal file
View File

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

View File

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

View File

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

144
src/dialog/splashdialog.ui Normal file
View File

@ -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">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:16pt; font-weight:600;&quot;&gt;-&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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