3 Copyright (c) 2012 Jakob Leben & Tim Blechmann
4 http://www.audiosynth.com
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "highlighter.hpp"
23 #include "autocompleter.hpp"
24 #include "../../core/doc_manager.hpp"
25 #include "../../core/settings/manager.hpp"
30 #include <QPaintEvent>
33 #include <QTextDocumentFragment>
38 LineIndicator::LineIndicator( CodeEditor
*editor
)
39 : QWidget( editor
), mEditor(editor
)
42 void LineIndicator::setLineCount( int count
)
45 setFixedWidth( widthForLineCount(count
) );
46 Q_EMIT( widthChanged() );
49 void LineIndicator::changeEvent( QEvent
*e
)
51 if( e
->type() == QEvent::FontChange
) {
52 setFixedWidth( widthForLineCount(mLineCount
) );
53 Q_EMIT( widthChanged() );
56 QWidget::changeEvent(e
);
59 void LineIndicator::paintEvent( QPaintEvent
*e
)
60 { mEditor
->paintLineIndicator(e
); }
62 int LineIndicator::widthForLineCount( int lineCount
)
65 while( lineCount
>= 100 ) {
70 return 6 + fontMetrics().width('9') * digits
;
73 CodeEditor::CodeEditor( QWidget
*parent
) :
74 QPlainTextEdit( parent
),
75 mLineIndicator( new LineIndicator(this) ),
79 mShowWhitespace(false),
80 mMouseBracketMatch(false),
81 mOverlay( new QGraphicsScene(this) ),
82 mAutoCompleter( new AutoCompleter(this) )
84 mLineIndicator
->move( contentsRect().topLeft() );
86 connect( this, SIGNAL(blockCountChanged(int)),
87 mLineIndicator
, SLOT(setLineCount(int)) );
89 connect( mLineIndicator
, SIGNAL( widthChanged() ),
90 this, SLOT( updateLayout() ) );
92 connect( this, SIGNAL(updateRequest(QRect
,int)),
93 this, SLOT(updateLineIndicator(QRect
,int)) );
95 connect( this, SIGNAL(cursorPositionChanged()),
96 this, SLOT(matchBrackets()) );
98 connect( mOverlay
, SIGNAL(changed(const QList
<QRectF
>&)),
99 this, SLOT(onOverlayChanged(const QList
<QRectF
>&)) );
101 mLineIndicator
->setLineCount(1);
104 void CodeEditor::setDocument( Document
*doc
)
106 QTextDocument
*tdoc
= doc
->textDocument();
107 new SyntaxHighlighter(tdoc
);
109 QFontMetricsF
fm(font());
112 opt
.setTabStop( fm
.width(' ') * mIndentWidth
);
114 opt
.setFlags( QTextOption::ShowTabsAndSpaces
);
116 tdoc
->setDefaultTextOption(opt
);
117 tdoc
->setDefaultFont(font());
118 tdoc
->setDocumentLayout( new QPlainTextDocumentLayout(tdoc
) );
120 QPlainTextEdit::setDocument(tdoc
);
122 mLineIndicator
->setLineCount( tdoc
->blockCount() );
126 mAutoCompleter
->documentChanged(tdoc
);
129 void CodeEditor::setIndentWidth( int width
)
131 mIndentWidth
= width
;
133 QTextDocument
*tdoc
= QPlainTextEdit::document();
135 QFontMetricsF
fm(font());
138 opt
.setTabStop( fm
.width(' ') * mIndentWidth
);
140 opt
.setFlags( QTextOption::ShowTabsAndSpaces
);
142 tdoc
->setDefaultTextOption(opt
);
145 static bool findInBlock(QTextDocument
*doc
, const QTextBlock
&block
, const QRegExp
&expr
, int offset
,
146 QTextDocument::FindFlags options
, QTextCursor
&cursor
)
148 QString text
= block
.text();
149 if(options
& QTextDocument::FindBackward
)
150 text
.truncate(offset
);
151 text
.replace(QChar::Nbsp
, QLatin1Char(' '));
154 while (offset
>=0 && offset
<= text
.length()) {
155 idx
= (options
& QTextDocument::FindBackward
) ?
156 expr
.lastIndexIn(text
, offset
) : expr
.indexIn(text
, offset
);
160 if (options
& QTextDocument::FindWholeWords
) {
161 const int start
= idx
;
162 const int end
= start
+ expr
.matchedLength();
163 if ((start
!= 0 && text
.at(start
- 1).isLetterOrNumber())
164 || (end
!= text
.length() && text
.at(end
).isLetterOrNumber())) {
165 //if this is not a whole word, continue the search in the string
166 offset
= (options
& QTextDocument::FindBackward
) ? idx
-1 : end
+1;
171 //we have a hit, return the cursor for that.
178 cursor
= QTextCursor(doc
);
179 cursor
.setPosition(block
.position() + idx
);
180 cursor
.setPosition(cursor
.position() + expr
.matchedLength(), QTextCursor::KeepAnchor
);
184 bool CodeEditor::find( const QRegExp
&expr
, QTextDocument::FindFlags options
)
186 // Although QTextDocument provides a find() method, we implement
187 // our own, because the former one is not adequate.
189 if(expr
.isEmpty()) return true;
191 bool backwards
= options
& QTextDocument::FindBackward
;
193 QTextCursor
c( textCursor() );
195 if (c
.hasSelection())
197 bool matching
= expr
.exactMatch(c
.selectedText());
199 if( backwards
== matching
)
200 pos
= c
.selectionStart();
202 pos
= c
.selectionEnd();
207 QTextDocument
*doc
= QPlainTextEdit::document();
208 QTextBlock startBlock
= doc
->findBlock(pos
);
209 int startBlockOffset
= pos
- startBlock
.position();
214 int blockOffset
= startBlockOffset
;
215 QTextBlock block
= startBlock
;
216 while (block
.isValid()) {
217 if (findInBlock(doc
, block
, expr
, blockOffset
, options
, cursor
))
220 block
= block
.next();
225 block
= doc
->begin();
227 if (findInBlock(doc
, block
, expr
, blockOffset
, options
, cursor
)
228 || block
== startBlock
)
230 block
= block
.next();
234 int blockOffset
= startBlockOffset
;
235 QTextBlock block
= startBlock
;
236 while (block
.isValid()) {
237 if (findInBlock(doc
, block
, expr
, blockOffset
, options
, cursor
))
239 block
= block
.previous();
240 blockOffset
= block
.length() - 1;
246 blockOffset
= block
.length() - 1;
247 if (findInBlock(doc
, block
, expr
, blockOffset
, options
, cursor
)
248 || block
== startBlock
)
250 block
= block
.previous();
255 if(!cursor
.isNull()) {
256 QTextEdit::ExtraSelection extraSelection
;
257 extraSelection
.cursor
= cursor
;
258 extraSelection
.format
.setBackground(Qt::yellow
);
260 cursor
.setPosition(cursor
.selectionEnd());
261 setTextCursor(cursor
);
263 QList
<QTextEdit::ExtraSelection
> selections
= extraSelections();
264 selections
.append(extraSelection
);
265 setExtraSelections(selections
);
273 int CodeEditor::findAll( const QRegExp
&expr
, QTextDocument::FindFlags options
)
275 mSearchSelections
.clear();
278 updateExtraSelections();
282 QTextEdit::ExtraSelection selection
;
283 selection
.format
.setBackground(Qt::darkYellow
);
285 QTextDocument
*doc
= QPlainTextEdit::document();
286 QTextBlock block
= doc
->begin();
289 while (block
.isValid()) {
290 int blockPos
= block
.position();
292 while(findInBlock(doc
, block
, expr
, offset
, options
, cursor
))
294 offset
= cursor
.selectionEnd() - blockPos
;
295 selection
.cursor
= cursor
;
296 mSearchSelections
.append(selection
);
298 block
= block
.next();
301 updateExtraSelections();
303 return mSearchSelections
.count();
306 //#define CSTR(QSTR) QSTR.toStdString().c_str()
308 static QString
resolvedReplacement( const QString
&replacement
, const QRegExp
&expr
)
311 static const QRegExp
rexpr("(\\\\\\\\)|(\\\\[0-9]+)");
312 QString
str( replacement
);
314 while(i
< str
.size() && ((i
= rexpr
.indexIn(str
, i
)) != -1))
316 int len
= rexpr
.matchedLength();
317 if(rexpr
.pos(1) != -1)
319 //qDebug("%i (%s): escape", i, CSTR(rexpr.cap(1)));
320 str
.replace(i
, len
, "\\");
323 else if(rexpr
.pos(2) != -1)
325 QString num_str
= rexpr
.cap(2);
326 num_str
.remove(0, 1);
327 int num
= num_str
.toInt();
328 //qDebug("%i (%s): backref = %i", i, CSTR(rexpr.cap(2)), num);
329 if(num
<= expr
.captureCount())
331 QString cap
= expr
.cap(num
);
332 //qDebug("resolving ref to: %s", CSTR(cap));
333 str
.replace(i
, len
, cap
);
338 //qDebug("ref out of range", i, num);
344 //qDebug("%i (%s): unknown match", i, CSTR(rexpr.cap(0)));
347 //qDebug(">> [%s] %i", CSTR(str), i);
353 bool CodeEditor::replace( const QRegExp
&expr
, const QString
&replacement
, QTextDocument::FindFlags options
)
355 if(expr
.isEmpty()) return true;
357 QTextCursor cursor
= textCursor();
358 if (cursor
.hasSelection() && expr
.exactMatch(cursor
.selectedText()))
360 QString rstr
= replacement
;
361 if(expr
.patternSyntax() != QRegExp::FixedString
)
362 rstr
= resolvedReplacement(rstr
, expr
);
363 cursor
.insertText(rstr
);
366 return find(expr
, options
);
369 int CodeEditor::replaceAll( const QRegExp
&expr
, const QString
&replacement
, QTextDocument::FindFlags options
)
371 mSearchSelections
.clear();
372 updateExtraSelections();
374 if(expr
.isEmpty()) return 0;
376 int replacements
= 0;
377 bool caps
= expr
.patternSyntax() != QRegExp::FixedString
;
379 QTextDocument
*doc
= QPlainTextEdit::document();
380 QTextBlock block
= doc
->begin();
383 QTextCursor(doc
).beginEditBlock();
385 while (block
.isValid())
387 int blockPos
= block
.position();
389 while(findInBlock(doc
, block
, expr
, offset
, options
, cursor
))
391 QString rstr
= replacement
;
393 rstr
= resolvedReplacement(rstr
, expr
);
394 cursor
.insertText(rstr
);
396 offset
= cursor
.selectionEnd() - blockPos
;
398 block
= block
.next();
401 QTextCursor(doc
).endEditBlock();
406 QTextCursor
CodeEditor::currentRegion()
408 QTextCursor
c(textCursor());
409 QTextBlock
b(c
.block());
411 int pos
= c
.position() - b
.position();
417 // search unmatched opening bracket
418 TokenIterator it
= TokenIterator::leftOf( b
, pos
);
421 char chr
= it
->character
;
424 if(level
> topLevel
) {
429 else if(chr
== ')') {
436 // no unmatched opening bracket
437 return QTextCursor();
439 // match the found opening bracket
440 it
= TokenIterator::rightOf( b
, pos
);
443 char chr
= it
->character
;
458 if(start
.isValid() && end
.isValid())
460 // only care about brackets at beginning of a line
461 if(start
->position
!= 0)
462 return QTextCursor();
464 // check whether the bracket makes part of an event
467 if (it
->type
== Token::SymbolArg
)
468 return QTextCursor();
471 if (it
.isValid() && it
->character
== ':')
472 return QTextCursor();
476 // ok, this is is a real top-level region
477 QTextCursor
c(QPlainTextEdit::document());
478 c
.setPosition(start
.position() + 1);
479 c
.setPosition(end
.position(), QTextCursor::KeepAnchor
);
483 return QTextCursor();
486 void CodeEditor::showPosition( int pos
)
490 QTextDocument
*doc
= QPlainTextEdit::document();
493 int lineNumber
= doc
->findBlock(pos
).firstLineNumber();
494 verticalScrollBar()->setValue(lineNumber
);
496 QTextCursor
cursor(doc
);
497 cursor
.setPosition(pos
);
498 setTextCursor(cursor
);
501 void CodeEditor::clearSearchHighlighting()
503 mSearchSelections
.clear();
504 updateExtraSelections();
507 void CodeEditor::zoomIn(int steps
)
510 qreal size
= f
.pointSizeF();
512 f
.setPointSizeF( size
+ steps
);
514 f
.setPixelSize( f
.pixelSize() + steps
);
519 void CodeEditor::zoomOut(int steps
)
522 qreal size
= f
.pointSizeF();
524 f
.setPointSizeF( qMax(1.0, size
- steps
) );
526 f
.setPixelSize( qMax(1, f
.pixelSize() - steps
) );
532 void CodeEditor::setShowWhitespace(bool show
)
534 mShowWhitespace
= show
;
536 QTextDocument
*doc
= QPlainTextEdit::document();
537 QTextOption
opt( doc
->defaultTextOption() );
539 opt
.setFlags( opt
.flags() | QTextOption::ShowTabsAndSpaces
);
541 opt
.setFlags( opt
.flags() & ~QTextOption::ShowTabsAndSpaces
);
542 doc
->setDefaultTextOption(opt
);
545 void CodeEditor::applySettings( Settings::Manager
*s
)
547 s
->beginGroup("IDE/editor");
549 mSpaceIndent
= s
->value("spaceIndent").toBool();
551 setIndentWidth( s
->value("indentWidth").toInt() );
556 fnt
.fromString( s
->value("font").toString() );
558 s
->beginGroup("colors");
560 if (s
->contains("background"))
561 plt
.setColor(QPalette::Base
, s
->value("background").value
<QColor
>());
563 if (s
->contains("text"))
564 plt
.setColor(QPalette::Text
, s
->value("text").value
<QColor
>());
567 if (s
->contains("lineNumbersBackground"))
568 lineNumPlt
.setColor(QPalette::Button
, s
->value("lineNumbersBackground").value
<QColor
>());
569 if (s
->contains("lineNumbers"))
570 lineNumPlt
.setColor(QPalette::ButtonText
, s
->value("lineNumbers").value
<QColor
>());
571 mLineIndicator
->setPalette(lineNumPlt
);
573 mBracketHighlight
= s
->value("matchingBrackets").value
<QColor
>();
575 s
->endGroup(); // colors
583 void CodeEditor::deleteTrailingSpaces()
585 document()->deleteTrailingSpaces();
588 bool CodeEditor::event( QEvent
*e
)
592 case QEvent::KeyPress
:
594 QKeyEvent
*ke
= static_cast<QKeyEvent
*>(e
);
599 case Qt::Key_Backtab
:
609 return QPlainTextEdit::event(e
);
612 void CodeEditor::changeEvent( QEvent
*e
)
614 if( e
->type() == QEvent::FontChange
) {
615 // adjust tab stop to match mIndentWidth * width of space
616 QTextDocument
*doc
= QPlainTextEdit::document();
617 QFontMetricsF
fm(font());
618 QTextOption
opt( doc
->defaultTextOption() );
619 opt
.setTabStop( fm
.width(' ') * mIndentWidth
);
620 doc
->setDefaultTextOption(opt
);
623 QPlainTextEdit::changeEvent(e
);
626 void CodeEditor::keyPressEvent( QKeyEvent
*e
)
631 Qt::KeyboardModifiers
mods(e
->modifiers());
632 if (mods
&& mods
!= Qt::ShiftModifier
) break;
634 QTextCursor::MoveMode mode
=
635 mods
& Qt::ShiftModifier
? QTextCursor::KeepAnchor
: QTextCursor::MoveAnchor
;
637 QTextCursor
c(textCursor());
638 QTextBlock
b(c
.block());
640 int pos
= indentedStartOfLine(b
);
643 if (c
.position() == pos
)
644 c
.movePosition(QTextCursor::StartOfLine
, mode
);
646 c
.setPosition(pos
, mode
);
655 QPlainTextEdit::keyPressEvent(e
);
660 case Qt::Key_BraceRight
:
661 case Qt::Key_BracketRight
:
668 mAutoCompleter
->keyPress(e
);
671 void CodeEditor::mouseReleaseEvent ( QMouseEvent
*e
)
673 // Prevent deselection of bracket match:
674 if(!mMouseBracketMatch
)
675 QPlainTextEdit::mouseReleaseEvent(e
);
677 mMouseBracketMatch
= false;
680 void CodeEditor::mouseDoubleClickEvent ( QMouseEvent
*e
)
682 QTextCursor
c(textCursor());
685 matchBracket( c
.position(), m
);
686 if(m
.first
.isValid() && m
.second
.isValid())
688 c
.setPosition(m
.first
.position());
689 c
.setPosition(m
.second
.position() + 1, QTextCursor::KeepAnchor
);
691 mMouseBracketMatch
= true;
695 QPlainTextEdit::mouseDoubleClickEvent(e
);
699 void CodeEditor::mouseMoveEvent( QMouseEvent
*e
)
701 // Prevent initiating a text drag:
702 if(!mMouseBracketMatch
)
703 QPlainTextEdit::mouseMoveEvent(e
);
706 void CodeEditor::onOverlayChanged ( const QList
<QRectF
> & region
)
708 foreach(QRectF r
, region
)
710 viewport()->update(r
.toRect());
714 void CodeEditor::paintEvent( QPaintEvent
*e
)
716 QPlainTextEdit::paintEvent(e
);
718 QPainter
p(viewport());
719 mOverlay
->render(&p
, e
->rect(), e
->rect());
722 void CodeEditor::updateLayout()
724 setViewportMargins( mLineIndicator
->width(), 0, 0, 0 );
727 void CodeEditor::updateLineIndicator( QRect r
, int dy
)
730 mLineIndicator
->scroll(0, dy
);
732 mLineIndicator
->update(0, r
.y(), mLineIndicator
->width(), r
.height() );
735 void CodeEditor::matchBrackets()
737 mBracketSelections
.clear();
739 QTextCursor
cursor(textCursor());
742 matchBracket( cursor
.position(), match
);
744 if( match
.first
.isValid() && match
.second
.isValid() )
746 const Token
& tok1
= *match
.first
;
747 const Token
& tok2
= *match
.second
;
750 (tok1
.character
== '(' && tok2
.character
== ')')
751 || (tok1
.character
== '[' && tok2
.character
== ']')
752 || (tok1
.character
== '{' && tok2
.character
== '}')
754 QTextEdit::ExtraSelection selection
;
755 selection
.format
.setFontWeight(QFont::Bold
);
756 selection
.format
.setBackground(mBracketHighlight
);
758 cursor
.setPosition(match
.first
.position());
759 cursor
.movePosition(QTextCursor::NextCharacter
, QTextCursor::KeepAnchor
);
760 selection
.cursor
= cursor
;
761 mBracketSelections
.append(selection
);
763 cursor
.setPosition(match
.second
.position());
764 cursor
.movePosition(QTextCursor::NextCharacter
, QTextCursor::KeepAnchor
);
765 selection
.cursor
= cursor
;
766 mBracketSelections
.append(selection
);
769 QTextEdit::ExtraSelection selection
;
770 selection
.format
.setBackground(Qt::red
);
771 cursor
.setPosition(match
.first
.position());
772 cursor
.setPosition(match
.second
.position()+1, QTextCursor::KeepAnchor
);
773 selection
.cursor
= cursor
;
774 mBracketSelections
.append(selection
);
778 updateExtraSelections();
781 void CodeEditor::matchBracket( int pos
, BracketMatch
& match
)
783 QTextBlock
block( textDocument()->findBlock(pos
) );
784 if (!block
.isValid())
787 int posInBlock
= pos
- block
.position();
788 TokenIterator
it(block
);
790 while (it
.isValid() && it
.block() == block
)
792 const Token
& token
= *it
;
793 if (token
.position
> posInBlock
)
796 (token
.position
== posInBlock
&& token
.type
== Token::OpeningBracket
) ||
797 (token
.position
== posInBlock
- 1 && token
.type
== Token::ClosingBracket
)
803 if( !it
.isValid() || it
.block() != block
)
806 if(it
->type
== Token::OpeningBracket
)
810 while((++it
).isValid())
812 Token::Type type
= it
->type
;
813 if(type
== Token::ClosingBracket
)
815 else if(type
== Token::OpeningBracket
)
823 else if(it
->type
== Token::ClosingBracket
)
827 while((--it
).isValid())
829 Token::Type type
= it
->type
;
830 if(type
== Token::OpeningBracket
)
832 else if(type
== Token::ClosingBracket
)
842 int CodeEditor::indentedStartOfLine( const QTextBlock
&b
)
849 if (c
!= ' ' && c
!= '\t')
857 void CodeEditor::updateExtraSelections()
859 QList
<QTextEdit::ExtraSelection
> selections
;
860 selections
.append(mBracketSelections
);
861 selections
.append(mSearchSelections
);
862 setExtraSelections(selections
);
865 void CodeEditor::resizeEvent( QResizeEvent
*e
)
867 QPlainTextEdit::resizeEvent( e
);
869 QRect cr
= contentsRect();
870 mLineIndicator
->resize( mLineIndicator
->width(), cr
.height() );
873 void CodeEditor::paintLineIndicator( QPaintEvent
*e
)
875 QPalette
plt( mLineIndicator
->palette() );
876 QRect
r( e
->rect() );
877 QPainter
p( mLineIndicator
);
879 p
.fillRect( r
, plt
.color( QPalette::Button
) );
880 p
.setPen( plt
.color(QPalette::ButtonText
) );
881 p
.drawLine( r
.topRight(), r
.bottomRight() );
883 QTextBlock block
= firstVisibleBlock();
884 int blockNumber
= block
.blockNumber();
885 int top
= (int) blockBoundingGeometry(block
).translated(contentOffset()).top();
886 int bottom
= top
+ (int) blockBoundingRect(block
).height();
888 while (block
.isValid() && top
<= e
->rect().bottom()) {
889 if (block
.isVisible() && bottom
>= e
->rect().top()) {
890 QString number
= QString::number(blockNumber
+ 1);
891 p
.drawText(0, top
, mLineIndicator
->width() - 4, fontMetrics().height(),
892 Qt::AlignRight
, number
);
895 block
= block
.next();
897 bottom
= top
+ (int) blockBoundingRect(block
).height();
902 void CodeEditor::indent()
904 QTextCursor cursor
= textCursor();
905 if (cursor
.selection().isEmpty())
908 indentCurrentSelection();
911 int CodeEditor::findIndentationLevel(QTextBlock
const & block
)
913 if (!block
.isValid())
916 TokenIterator it
= TokenIterator::leftOf(block
, 0);
921 TokenIterator
next(block
);
922 if (next
.isValid() && next
->type
== Token::ClosingBracket
)
925 while (it
.isValid()) {
926 if (it
->type
== Token::OpeningBracket
&& it
->character
!= '(')
928 else if (it
->type
== Token::ClosingBracket
&& it
->character
!= ')')
936 return qMax(level
, 0);
939 void CodeEditor::indentCurrentSelection()
941 QTextCursor cursor
= textCursor();
943 const int position
= cursor
.position();
944 const int anchor
= cursor
.anchor();
946 QTextDocument
* doc
= QPlainTextEdit::document();
947 QTextBlock block
= doc
->findBlock(qMin(position
, anchor
));
948 QTextBlock endBlock
= anchor
!= position
? doc
->findBlock(qMax(position
, anchor
))
951 cursor
.beginEditBlock();
954 cursor
.setPosition(block
.position());
955 indentLineAtCursor(cursor
);
957 if ( block
!= endBlock
)
958 block
= block
.next();
963 cursor
.endEditBlock();
966 void CodeEditor::indentCurrentLine()
968 QTextCursor cursor
= textCursor();
969 cursor
.beginEditBlock();
970 indentLineAtCursor(textCursor());
971 cursor
.endEditBlock();
974 void CodeEditor::indentLineAtCursor(QTextCursor cursor
)
976 const int indentationLevel
= findIndentationLevel(cursor
.block());
978 cursor
.movePosition(QTextCursor::StartOfBlock
);
979 cursor
.setPosition(cursor
.position() + indentedStartOfLine(cursor
.block()), QTextCursor::KeepAnchor
);
981 if ( mSpaceIndent
) {
982 const int spaces
= mIndentWidth
* indentationLevel
;
983 QString
replacement (spaces
, QChar(' '));
984 cursor
.insertText(replacement
);
986 const int tabs
= indentationLevel
;
987 QString
replacement (tabs
, QChar('\t'));
988 cursor
.insertText(replacement
);