Test your websites with this simple GUI based scripted webtester. Generate simple testscripts directly from surfng on the webpage, enhance them with your commands, with variables, loops, checks, … and finally run automated web tests.
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
189 lines
6.9 KiB
189 lines
6.9 KiB
#ifndef EDITOR_HXX |
|
#define EDITOR_HXX |
|
/// from qt http://doc.qt.io/qt-5/qtwidgets-widgets-codeeditor-example.html |
|
|
|
#include <QPlainTextEdit> |
|
#include <QPainter> |
|
#include <QTextBlock> |
|
#include <QResizeEvent> |
|
#include <QSyntaxHighlighter> |
|
#include <QRegularExpression> |
|
#include <QRegularExpressionMatch> |
|
#include <cassert> |
|
|
|
#include <iostream> |
|
|
|
class Highlighter: public QSyntaxHighlighter { |
|
Q_OBJECT |
|
Q_SIGNALS: |
|
void include(QString); |
|
public: |
|
Highlighter(QTextDocument *parent): QSyntaxHighlighter(parent) { |
|
QString commands="auth|ca-certificate|call|case|default|check|clear-cookies|click|clicktype|client-certificate|do|download|echo|execute|exists|exit|expect|fail|for|function|if|else|while|ignore|unignore|ignoreto|include|label|load|not|offline-storage-path|open|screenshot|set|setvalue|sleep|testcase|testsuite|timeout|timeout-false|unset|upload"; |
|
_expressions<<Expression("^ *("+commands+")\\b").weight(QFont::Bold).fg(Qt::darkBlue) |
|
<<Expression("^ *#.*$").weight(QFont::Bold).fg(Qt::black); |
|
} |
|
protected: |
|
void highlightBlock(const QString &text) { |
|
static QRegularExpression inc("^ *include +([^ ].*.\\.wt)"); |
|
QRegularExpressionMatch m(inc.match(text)); |
|
if (m.hasMatch()) { |
|
QTextCharFormat fmt; |
|
if (QFile(m.captured(1)).exists()) { |
|
fmt.setForeground(Qt::darkGreen); |
|
fmt.setFontWeight(QFont::Bold); |
|
} else { |
|
fmt.setForeground(Qt::darkRed); |
|
fmt.setFontStrikeOut(true); |
|
} |
|
setFormat(m.capturedStart(1), m.capturedLength(1), fmt); |
|
include(m.captured(1)); |
|
} |
|
for (auto e: _expressions) { |
|
auto m2(e.re.match(text)); |
|
for (int i(0); i<=m2.lastCapturedIndex(); ++i) { |
|
setFormat(m2.capturedStart(i), m2.capturedLength(i), e.fmt); |
|
} |
|
} |
|
} |
|
private: |
|
struct Expression { |
|
Expression(QString s): re(s) {} |
|
Expression(QString s, QTextCharFormat f): re(s), fmt(f) {} |
|
Expression& weight(int w) {fmt.setFontWeight(w); return *this;} |
|
Expression& strike(bool s=true) {fmt.setFontStrikeOut(s); return *this;} |
|
Expression& fg(const QBrush& b) {fmt.setForeground(b); return *this;} |
|
QRegularExpression re; |
|
QTextCharFormat fmt; |
|
}; |
|
QList<Expression> _expressions; |
|
}; |
|
|
|
class CodeEditor; |
|
|
|
class LineNumberArea: public QWidget { |
|
public: |
|
LineNumberArea(CodeEditor *editor); |
|
QSize sizeHint() const override; |
|
protected: |
|
void paintEvent(QPaintEvent *event) override; |
|
private: |
|
CodeEditor *codeEditor; |
|
}; |
|
|
|
class CodeEditor: public QPlainTextEdit { |
|
Q_OBJECT; |
|
Q_SIGNALS: |
|
void include(QString); |
|
void link(QString); |
|
public Q_SLOTS: |
|
void gotoLine(int line) { |
|
if (textCursor().blockNumber()==line-1) return; |
|
QTextCursor cursor(document()->findBlockByNumber(line-1)); |
|
setTextCursor(cursor); |
|
highlightCurrentLine(); |
|
} |
|
public: |
|
CodeEditor(QWidget *parent = 0): QPlainTextEdit(parent) { |
|
Highlighter *highlighter(new Highlighter(document())); |
|
lineNumberArea = new LineNumberArea(this); |
|
assert(connect(this, SIGNAL(blockCountChanged(int)), SLOT(updateLineNumberAreaWidth(int)))); |
|
assert(connect(this, SIGNAL(updateRequest(QRect,int)), SLOT(updateLineNumberArea(QRect,int)))); |
|
assert(connect(this, SIGNAL(cursorPositionChanged()), SLOT(highlightCurrentLine()))); |
|
assert(connect(highlighter, SIGNAL(include(QString)), SIGNAL(include(QString)))); |
|
updateLineNumberAreaWidth(0); |
|
highlightCurrentLine(); |
|
} |
|
void lineNumberAreaPaintEvent(QPaintEvent *event) { |
|
QPainter painter(lineNumberArea); |
|
painter.fillRect(event->rect(), Qt::lightGray); |
|
QTextBlock block = firstVisibleBlock(); |
|
int blockNumber = block.blockNumber(); |
|
int top = (int) blockBoundingGeometry(block).translated(contentOffset()).top(); |
|
int bottom = top + (int) blockBoundingRect(block).height(); |
|
while (block.isValid() && top <= event->rect().bottom()) { |
|
if (block.isVisible() && bottom >= event->rect().top()) { |
|
QString number = QString::number(blockNumber + 1); |
|
painter.setPen(Qt::black); |
|
painter.drawText(0, top, lineNumberArea->width(), fontMetrics().height(), |
|
Qt::AlignRight, number); |
|
} |
|
block = block.next(); |
|
top = bottom; |
|
bottom = top + (int) blockBoundingRect(block).height(); |
|
++blockNumber; |
|
} |
|
} |
|
int lineNumberAreaWidth() { |
|
int digits(1); |
|
int max = qMax(1, blockCount()); |
|
while (max >= 10) { |
|
max /= 10; |
|
++digits; |
|
} |
|
int space = 3 + fontMetrics().width(QLatin1Char('9')) * digits; |
|
return space; |
|
} |
|
void mousePressEvent(QMouseEvent *e) { |
|
clickedAnchor = (e->button() & Qt::LeftButton) |
|
? document()->findBlock(cursorForPosition(e->pos()).position()).text() |
|
: QString(); |
|
QPlainTextEdit::mousePressEvent(e); |
|
} |
|
void mouseReleaseEvent(QMouseEvent *e) { |
|
if (e->button() & Qt::LeftButton && !clickedAnchor.isEmpty() |
|
&& document()->findBlock(cursorForPosition(e->pos()).position()).text() == clickedAnchor) { |
|
static QRegularExpression inc("^ *include +([^ ].*.\\.wt)"); |
|
QRegularExpressionMatch m(inc.match(clickedAnchor)); |
|
if (m.hasMatch() && QFile(m.captured(1)).exists()) { |
|
link(m.captured(1)); |
|
} |
|
} |
|
QPlainTextEdit::mouseReleaseEvent(e); |
|
} |
|
protected: |
|
void resizeEvent(QResizeEvent *e) override { |
|
QPlainTextEdit::resizeEvent(e); |
|
QRect cr = contentsRect(); |
|
lineNumberArea->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height())); |
|
} |
|
private Q_SLOTS: |
|
void updateLineNumberAreaWidth(int newBlockCount) { |
|
setViewportMargins(lineNumberAreaWidth(), 0, 0, 0); |
|
} |
|
void highlightCurrentLine() { |
|
QList<QTextEdit::ExtraSelection> extraSelections; |
|
if (!isReadOnly()) { |
|
QTextEdit::ExtraSelection selection; |
|
QColor lineColor = QColor(Qt::yellow).lighter(160); |
|
selection.format.setBackground(lineColor); |
|
selection.format.setProperty(QTextFormat::FullWidthSelection, true); |
|
selection.cursor = textCursor(); |
|
selection.cursor.clearSelection(); |
|
extraSelections.append(selection); |
|
} |
|
setExtraSelections(extraSelections); |
|
} |
|
void updateLineNumberArea(const QRect &rect, int dy) { |
|
if (dy) |
|
lineNumberArea->scroll(0, dy); |
|
else |
|
lineNumberArea->update(0, rect.y(), lineNumberArea->width(), rect.height()); |
|
if (rect.contains(viewport()->rect())) |
|
updateLineNumberAreaWidth(0); |
|
} |
|
private: |
|
QWidget *lineNumberArea; |
|
QString clickedAnchor; |
|
}; |
|
|
|
inline LineNumberArea::LineNumberArea(CodeEditor *editor): QWidget(editor) { |
|
codeEditor = editor; |
|
} |
|
inline QSize LineNumberArea::sizeHint() const { |
|
return QSize(codeEditor->lineNumberAreaWidth(), 0); |
|
} |
|
inline void LineNumberArea::paintEvent(QPaintEvent *event) { |
|
codeEditor->lineNumberAreaPaintEvent(event); |
|
} |
|
#endif
|
|
|