660 lines
23 KiB
C++
660 lines
23 KiB
C++
//=============================================================================
|
|
// MuseScore
|
|
// Music Composition & Notation
|
|
//
|
|
// Copyright (C) 2002-2011 Werner Schweer
|
|
//
|
|
// This program is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License version 2
|
|
// as published by the Free Software Foundation and appearing in
|
|
// the file LICENCE.GPL
|
|
//
|
|
// Syntax highlighter based on example code from Ariya Hidayat
|
|
// (git://gitorious.org/ofi-labs/x2.git BSD licensed).
|
|
//=============================================================================
|
|
|
|
#include "qmledit.h"
|
|
#include "musescore.h"
|
|
|
|
namespace Ms {
|
|
|
|
//---------------------------------------------------------
|
|
// JSHighlighter
|
|
//---------------------------------------------------------
|
|
|
|
JSHighlighter::JSHighlighter(QTextDocument *parent)
|
|
: QSyntaxHighlighter(parent)
|
|
, m_markCaseSensitivity(Qt::CaseInsensitive)
|
|
{
|
|
// default color scheme
|
|
m_colors[QmlEdit::Normal] = QColor("#000000");
|
|
m_colors[QmlEdit::Comment] = QColor("#808080");
|
|
m_colors[QmlEdit::Number] = QColor("#008000");
|
|
m_colors[QmlEdit::String] = QColor("#800000");
|
|
m_colors[QmlEdit::Operator] = QColor("#808000");
|
|
m_colors[QmlEdit::Identifier] = QColor("#000020");
|
|
m_colors[QmlEdit::Keyword] = QColor("#000080");
|
|
m_colors[QmlEdit::BuiltIn] = QColor("#008080");
|
|
m_colors[QmlEdit::Marker] = QColor("#ffff00");
|
|
|
|
// https://developer.mozilla.org/en/JavaScript/Reference/Reserved_Words
|
|
|
|
static const char* data1[] = { "break", "case", "catch", "continue",
|
|
"default", "delete", "do", "else", "finally", "for", "function",
|
|
"if", "in", "instanceof", "new", "return", "switch", "this", "throw",
|
|
"try", "typeof", "var", "void", "while", "with", "true", "false",
|
|
"null" };
|
|
|
|
for (unsigned int i = 0; i < sizeof(data1)/sizeof(*data1); ++i)
|
|
m_keywords.insert(data1[i]);
|
|
|
|
// built-in and other popular objects + properties
|
|
|
|
static const char* data2[] = { "Object", "prototype", "create",
|
|
"defineProperty", "defineProperties", "getOwnPropertyDescriptor",
|
|
"keys", "getOwnPropertyNames", "constructor", "__parent__", "__proto__",
|
|
"__defineGetter__", "__defineSetter__", "eval", "hasOwnProperty",
|
|
"isPrototypeOf", "__lookupGetter__", "__lookupSetter__", "__noSuchMethod__",
|
|
"propertyIsEnumerable", "toSource", "toLocaleString", "toString",
|
|
"unwatch", "valueOf", "watch", "Function", "arguments", "arity", "caller",
|
|
"constructor", "length", "name", "apply", "bind", "call", "String",
|
|
"fromCharCode", "length", "charAt", "charCodeAt", "concat", "indexOf",
|
|
"lastIndexOf", "localCompare", "match", "quote", "replace", "search",
|
|
"slice", "split", "substr", "substring", "toLocaleLowerCase",
|
|
"toLocaleUpperCase", "toLowerCase", "toUpperCase", "trim", "trimLeft",
|
|
"trimRight", "Array", "isArray", "index", "input", "pop", "push",
|
|
"reverse", "shift", "sort", "splice", "unshift", "concat", "join",
|
|
"filter", "forEach", "every", "map", "some", "reduce", "reduceRight",
|
|
"RegExp", "global", "ignoreCase", "lastIndex", "multiline", "source",
|
|
"exec", "test", "JSON", "parse", "stringify", "decodeURI",
|
|
"decodeURIComponent", "encodeURI", "encodeURIComponent", "eval",
|
|
"isFinite", "isNaN", "parseFloat", "parseInt", "Infinity", "NaN",
|
|
"undefined", "Math", "E", "LN2", "LN10", "LOG2E", "LOG10E", "PI",
|
|
"SQRT1_2", "SQRT2", "abs", "acos", "asin", "atan", "atan2", "ceil",
|
|
"cos", "exp", "floor", "log", "max", "min", "pow", "random", "round",
|
|
"sin", "sqrt", "tan", "document", "window", "navigator", "userAgent"
|
|
};
|
|
|
|
for (unsigned int i = 0; i < sizeof(data2)/sizeof(*data2); ++i)
|
|
m_knownIds.insert(data2[i]);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setColor
|
|
//---------------------------------------------------------
|
|
|
|
void JSHighlighter::setColor(QmlEdit::ColorComponent component, const QColor& color)
|
|
{
|
|
m_colors[component] = color;
|
|
rehighlight();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// highlightBlock
|
|
//---------------------------------------------------------
|
|
|
|
void JSHighlighter::highlightBlock(const QString& text)
|
|
{
|
|
// parsing state
|
|
enum class State : char {
|
|
Start = 0,
|
|
Number = 1,
|
|
Identifier = 2,
|
|
String = 3,
|
|
Comment = 4,
|
|
Regex = 5
|
|
};
|
|
|
|
QList<int> bracketPositions;
|
|
int blockState = previousBlockState();
|
|
int bracketLevel = blockState >> 4;
|
|
State state = State(blockState & 15);
|
|
if (blockState < 0) {
|
|
bracketLevel = 0;
|
|
state = State::Start;
|
|
}
|
|
int start = 0;
|
|
int i = 0;
|
|
while (i <= text.length()) {
|
|
QChar ch = (i < text.length()) ? text.at(i) : QChar();
|
|
QChar next = (i < text.length() - 1) ? text.at(i + 1) : QChar();
|
|
switch (state) {
|
|
case State::Start:
|
|
start = i;
|
|
if (ch.isSpace()) {
|
|
++i;
|
|
}
|
|
else if (ch.isDigit()) {
|
|
++i;
|
|
state = State::Number;
|
|
}
|
|
else if (ch.isLetter() || ch == '_') {
|
|
++i;
|
|
state = State::Identifier;
|
|
}
|
|
else if (ch == '\'' || ch == '\"') {
|
|
++i;
|
|
state = State::String;
|
|
}
|
|
else if (ch == '/' && next == '*') {
|
|
++i;
|
|
++i;
|
|
state = State::Comment;
|
|
}
|
|
else if (ch == '/' && next == '/') {
|
|
i = text.length();
|
|
setFormat(start, text.length(), m_colors[QmlEdit::Comment]);
|
|
}
|
|
else if (ch == '/' && next != '*') {
|
|
++i;
|
|
state = State::Regex;
|
|
}
|
|
else {
|
|
if (!QString("(){}[]").contains(ch))
|
|
setFormat(start, 1, m_colors[QmlEdit::Operator]);
|
|
if (ch =='{' || ch == '}') {
|
|
bracketPositions += i;
|
|
if (ch == '{')
|
|
bracketLevel++;
|
|
else
|
|
bracketLevel--;
|
|
}
|
|
++i;
|
|
state = State::Start;
|
|
}
|
|
break;
|
|
case State::Number:
|
|
if (ch.isSpace() || !ch.isDigit()) {
|
|
setFormat(start, i - start, m_colors[QmlEdit::Number]);
|
|
state = State::Start;
|
|
}
|
|
else {
|
|
++i;
|
|
}
|
|
break;
|
|
case State::Identifier:
|
|
if (ch.isSpace() || !(ch.isDigit() || ch.isLetter() || ch == '_')) {
|
|
QString token = text.mid(start, i - start).trimmed();
|
|
if (m_keywords.contains(token))
|
|
setFormat(start, i - start, m_colors[QmlEdit::Keyword]);
|
|
else if (m_knownIds.contains(token))
|
|
setFormat(start, i - start, m_colors[QmlEdit::BuiltIn]);
|
|
state = State::Start;
|
|
}
|
|
else {
|
|
++i;
|
|
}
|
|
break;
|
|
case State::String:
|
|
if (ch == text.at(start)) {
|
|
QChar prev = (i > 0) ? text.at(i - 1) : QChar();
|
|
if (prev != '\\') {
|
|
++i;
|
|
setFormat(start, i - start, m_colors[QmlEdit::String]);
|
|
state = State::Start;
|
|
}
|
|
else {
|
|
++i;
|
|
}
|
|
}
|
|
else {
|
|
++i;
|
|
}
|
|
break;
|
|
case State::Comment:
|
|
if (ch == '*' && next == '/') {
|
|
++i;
|
|
++i;
|
|
setFormat(start, i - start, m_colors[QmlEdit::Comment]);
|
|
state = State::Start;
|
|
}
|
|
else {
|
|
++i;
|
|
}
|
|
break;
|
|
case State::Regex:
|
|
if (ch == '/') {
|
|
QChar prev = (i > 0) ? text.at(i - 1) : QChar();
|
|
if (prev != '\\') {
|
|
++i;
|
|
setFormat(start, i - start, m_colors[QmlEdit::String]);
|
|
state = State::Start;
|
|
}
|
|
else {
|
|
++i;
|
|
}
|
|
}
|
|
else {
|
|
++i;
|
|
}
|
|
break;
|
|
default:
|
|
state = State::Start;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (state == State::Comment)
|
|
setFormat(start, text.length(), m_colors[QmlEdit::Comment]);
|
|
else
|
|
state = State::Start;
|
|
|
|
if (!m_markString.isEmpty()) {
|
|
int pos = 0;
|
|
int len = m_markString.length();
|
|
QTextCharFormat markerFormat;
|
|
markerFormat.setBackground(m_colors[QmlEdit::Marker]);
|
|
markerFormat.setForeground(m_colors[QmlEdit::Normal]);
|
|
for (;;) {
|
|
pos = text.indexOf(m_markString, pos, m_markCaseSensitivity);
|
|
if (pos < 0)
|
|
break;
|
|
setFormat(pos, len, markerFormat);
|
|
++pos;
|
|
}
|
|
}
|
|
if (!bracketPositions.isEmpty()) {
|
|
JSBlockData *blockData = reinterpret_cast<JSBlockData*>(currentBlock().userData());
|
|
if (!blockData) {
|
|
blockData = new JSBlockData;
|
|
currentBlock().setUserData(blockData);
|
|
}
|
|
blockData->bracketPositions = bracketPositions;
|
|
}
|
|
blockState = (int(state) & 15) | (bracketLevel << 4);
|
|
setCurrentBlockState(blockState);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// mark
|
|
//---------------------------------------------------------
|
|
|
|
void JSHighlighter::mark(const QString &str, Qt::CaseSensitivity caseSensitivity)
|
|
{
|
|
m_markString = str;
|
|
m_markCaseSensitivity = caseSensitivity;
|
|
rehighlight();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// keywords
|
|
//---------------------------------------------------------
|
|
|
|
QStringList JSHighlighter::keywords() const
|
|
{
|
|
return m_keywords.toList();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// setKeywords
|
|
//---------------------------------------------------------
|
|
|
|
void JSHighlighter::setKeywords(const QStringList &keywords)
|
|
{
|
|
m_keywords = QSet<QString>::fromList(keywords);
|
|
rehighlight();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// Binding
|
|
//---------------------------------------------------------
|
|
|
|
struct Binding {
|
|
const char* name;
|
|
int key1, key2;
|
|
const char* slot;
|
|
};
|
|
|
|
//---------------------------------------------------------
|
|
// QmlEdit
|
|
//---------------------------------------------------------
|
|
|
|
QmlEdit::QmlEdit(QWidget* parent)
|
|
: QPlainTextEdit(parent)
|
|
{
|
|
setBackgroundVisible(true);
|
|
setLineWrapMode(QPlainTextEdit::NoWrap);
|
|
QFont font("FreeMono", 12);
|
|
font.setStyleHint(QFont::TypeWriter);
|
|
font.setFixedPitch(true);
|
|
setFont(font);
|
|
document()->setDefaultFont(font);
|
|
|
|
QTextCursor c = textCursor();
|
|
QTextCharFormat cf = c.charFormat();
|
|
cf.setFont(font);
|
|
c.setCharFormat(cf);
|
|
setTextCursor(c);
|
|
|
|
#if 0
|
|
static const Binding bindings[] = {
|
|
{ "start", Qt::CTRL+Qt::Key_Q, Qt::CTRL+Qt::Key_E, SLOT(start()) },
|
|
{ "end", Qt::CTRL+Qt::Key_Q, Qt::CTRL+Qt::Key_X, SLOT(end()) },
|
|
{ "startOfLine", Qt::CTRL+Qt::Key_Q, Qt::CTRL+Qt::Key_S, SLOT(startOfLine()) },
|
|
{ "endOfLine", Qt::CTRL+Qt::Key_Q, Qt::CTRL+Qt::Key_D, SLOT(endOfLine()) },
|
|
{ "up", Qt::CTRL+Qt::Key_E, 0, SLOT(upLine()) },
|
|
{ "down", Qt::CTRL+Qt::Key_X, 0, SLOT(downLine()) },
|
|
{ "right", Qt::CTRL+Qt::Key_D, 0, SLOT(right()) },
|
|
{ "left", Qt::CTRL+Qt::Key_S, 0, SLOT(left()) },
|
|
{ "rightWord", Qt::CTRL+Qt::Key_F, 0, SLOT(rightWord()) },
|
|
{ "leftWord", Qt::CTRL+Qt::Key_A, 0, SLOT(leftWord()) },
|
|
{ "pick", Qt::Key_F8, 0, SLOT(pick()) },
|
|
{ "put", Qt::Key_F9, 0, SLOT(put()) },
|
|
{ "delLine", Qt::CTRL+Qt::Key_Y, 0, SLOT(delLine()) },
|
|
{ "delWord", Qt::CTRL+Qt::Key_T, 0, SLOT(delWord()) }
|
|
};
|
|
#endif
|
|
setTabChangesFocus(false);
|
|
setBackgroundVisible(false);
|
|
setCursorWidth(3);
|
|
|
|
QPalette p = palette();
|
|
p.setColor(QPalette::Text, Qt::black);
|
|
p.setColor(QPalette::Base, QColor(0xe0, 0xe0, 0xe0));
|
|
setPalette(p);
|
|
hl = new JSHighlighter(document());
|
|
lineNumberArea = new LineNumberArea(this);
|
|
|
|
#if 0
|
|
for (unsigned int i = 0; i < sizeof(bindings)/sizeof(*bindings); ++i) {
|
|
const Binding& b = bindings[i];
|
|
QAction* a = new QAction(b.name, this);
|
|
a->setShortcut(QKeySequence(b.key1, b.key2));
|
|
a->setShortcutContext(Qt::WidgetShortcut);
|
|
a->setPriority(QAction::HighPriority);
|
|
addAction(a);
|
|
connect(a, SIGNAL(triggered()), b.slot);
|
|
}
|
|
#endif
|
|
|
|
connect(this, SIGNAL(blockCountChanged(int)), SLOT(updateLineNumberAreaWidth(int)));
|
|
connect(this, SIGNAL(updateRequest(QRect,int)), SLOT(updateLineNumberArea(QRect,int)));
|
|
connect(this, SIGNAL(cursorPositionChanged()), SLOT(highlightCurrentLine()));
|
|
|
|
updateLineNumberAreaWidth(0);
|
|
highlightCurrentLine();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// focusInEvent
|
|
//---------------------------------------------------------
|
|
|
|
void QmlEdit::focusInEvent(QFocusEvent* event)
|
|
{
|
|
mscoreState = mscore->state();
|
|
mscore->changeState(STATE_DISABLED);
|
|
QPlainTextEdit::focusInEvent(event);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// focusOutEvent
|
|
//---------------------------------------------------------
|
|
|
|
void QmlEdit::focusOutEvent(QFocusEvent* event)
|
|
{
|
|
mscore->changeState(mscoreState);
|
|
QPlainTextEdit::focusOutEvent(event);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// move
|
|
//---------------------------------------------------------
|
|
|
|
void QmlEdit::move(QTextCursor::MoveOperation op)
|
|
{
|
|
QTextCursor tc(textCursor());
|
|
tc.movePosition(op);
|
|
setTextCursor(tc);
|
|
update();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// QmlEdit
|
|
//---------------------------------------------------------
|
|
|
|
QmlEdit::~QmlEdit()
|
|
{
|
|
delete hl;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// lineNumberAreaWidth
|
|
//---------------------------------------------------------
|
|
|
|
int QmlEdit::lineNumberAreaWidth()
|
|
{
|
|
int digits = 1;
|
|
int max = qMax(1, blockCount());
|
|
while (max >= 10) {
|
|
max /= 10;
|
|
++digits;
|
|
}
|
|
int space = 6 + fontMetrics().width(QLatin1Char('9')) * digits;
|
|
return space;
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// updateLineNumberAreaWidth
|
|
//---------------------------------------------------------
|
|
|
|
void QmlEdit::updateLineNumberAreaWidth(int /* newBlockCount */)
|
|
{
|
|
setViewportMargins(lineNumberAreaWidth(), 0, 0, 0);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// updateLineNumberArea
|
|
//---------------------------------------------------------
|
|
|
|
void QmlEdit::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);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// resizeEvent
|
|
//---------------------------------------------------------
|
|
|
|
void QmlEdit::resizeEvent(QResizeEvent *e)
|
|
{
|
|
QPlainTextEdit::resizeEvent(e);
|
|
|
|
QRect cr = contentsRect();
|
|
lineNumberArea->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height()));
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// highlightCurrentLine
|
|
//---------------------------------------------------------
|
|
|
|
void QmlEdit::highlightCurrentLine()
|
|
{
|
|
QList<QTextEdit::ExtraSelection> extraSelections;
|
|
|
|
if (!isReadOnly()) {
|
|
QTextEdit::ExtraSelection selection;
|
|
|
|
QColor lineColor = QColor(Qt::white);
|
|
|
|
selection.format.setBackground(lineColor);
|
|
selection.format.setProperty(QTextFormat::FullWidthSelection, true);
|
|
selection.cursor = textCursor();
|
|
selection.cursor.clearSelection();
|
|
extraSelections.append(selection);
|
|
}
|
|
|
|
setExtraSelections(extraSelections);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// lineNumberAreaPaintEvent
|
|
//---------------------------------------------------------
|
|
|
|
void QmlEdit::lineNumberAreaPaintEvent(QPaintEvent *event)
|
|
{
|
|
QPainter painter(lineNumberArea);
|
|
painter.fillRect(event->rect(), Qt::lightGray);
|
|
|
|
QFont font("FreeMono", 12);
|
|
font.setStyleHint(QFont::TypeWriter);
|
|
font.setFixedPitch(true);
|
|
painter.setFont(font);
|
|
|
|
QTextBlock block = firstVisibleBlock();
|
|
int blockNumber = block.blockNumber();
|
|
int top = (int) blockBoundingGeometry(block).translated(contentOffset()).top();
|
|
int bottom = top + (int) blockBoundingRect(block).height();
|
|
|
|
int w = lineNumberArea->width();
|
|
int h = fontMetrics().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, w-3, h, Qt::AlignRight, number);
|
|
}
|
|
|
|
block = block.next();
|
|
top = bottom;
|
|
bottom = top + (int) blockBoundingRect(block).height();
|
|
++blockNumber;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// pick
|
|
//---------------------------------------------------------
|
|
|
|
void QmlEdit::pick()
|
|
{
|
|
pickBuffer = textCursor().block().text();
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// put
|
|
//---------------------------------------------------------
|
|
|
|
void QmlEdit::put()
|
|
{
|
|
QTextCursor c = textCursor();
|
|
int column = c.columnNumber();
|
|
c.movePosition(QTextCursor::StartOfBlock);
|
|
c.insertText(pickBuffer + "\n");
|
|
c.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, column);
|
|
c.movePosition(QTextCursor::Up);
|
|
setTextCursor(c);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// delLine
|
|
//---------------------------------------------------------
|
|
|
|
void QmlEdit::delLine()
|
|
{
|
|
QTextCursor c = textCursor();
|
|
c.select(QTextCursor::BlockUnderCursor);
|
|
pickBuffer = c.selectedText().mid(1);
|
|
c.removeSelectedText();
|
|
c.movePosition(QTextCursor::Down);
|
|
setTextCursor(c);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// delWord
|
|
//---------------------------------------------------------
|
|
|
|
void QmlEdit::delWord()
|
|
{
|
|
QTextCursor c = textCursor();
|
|
int i = c.position();
|
|
if (document()->characterAt(i) == QChar(' ')) {
|
|
while(document()->characterAt(i) == QChar(' '))
|
|
c.deleteChar();
|
|
}
|
|
else {
|
|
for (;;) {
|
|
QChar ch = document()->characterAt(i);
|
|
if (ch == QChar(' ') || ch == QChar('\n'))
|
|
break;
|
|
c.deleteChar();
|
|
}
|
|
while(document()->characterAt(i) == QChar(' '))
|
|
c.deleteChar();
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// downLine
|
|
//---------------------------------------------------------
|
|
|
|
void QmlEdit::downLine()
|
|
{
|
|
qDebug("Down line");
|
|
move(QTextCursor::Down);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// leftWord
|
|
//---------------------------------------------------------
|
|
|
|
void QmlEdit::leftWord()
|
|
{
|
|
QTextCursor c = textCursor();
|
|
|
|
if (c.positionInBlock() == 0)
|
|
return;
|
|
c.movePosition(QTextCursor::Left);
|
|
|
|
bool inSpace = true;
|
|
for (;c.positionInBlock();) {
|
|
int i = c.position();
|
|
if (document()->characterAt(i) == QChar(' ')) {
|
|
if (!inSpace) {
|
|
c.movePosition(QTextCursor::Right);
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
if (inSpace)
|
|
inSpace = false;
|
|
}
|
|
c.movePosition(QTextCursor::Left);
|
|
}
|
|
setTextCursor(c);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// keyPressEvent
|
|
//---------------------------------------------------------
|
|
|
|
void QmlEdit::keyPressEvent(QKeyEvent* event)
|
|
{
|
|
|
|
if (event->modifiers() != Qt::ControlModifier && event->key() == Qt::Key_Tab) {
|
|
tab();
|
|
event->accept();
|
|
return;
|
|
}
|
|
QPlainTextEdit::keyPressEvent(event);
|
|
}
|
|
|
|
//---------------------------------------------------------
|
|
// tab
|
|
//---------------------------------------------------------
|
|
|
|
void QmlEdit::tab()
|
|
{
|
|
QTextCursor c = textCursor();
|
|
c.insertText(" ");
|
|
while (c.positionInBlock() % 6)
|
|
c.insertText(" ");
|
|
setTextCursor(c);
|
|
}
|
|
}
|
|
|