1 // Copyright (C) 2015-2016 OPEN CASCADE
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 // File : PyEditor_Editor.cxx
20 // Author : Maxim GLIBIN, Open CASCADE S.A.S. (maxim.glibin@opencascade.com)
23 #include "PyEditor_Editor.h"
24 #include "PyEditor_LineNumberArea.h"
25 #include "PyEditor_PyHighlighter.h"
26 #include "PyEditor_Completer.h"
27 #include "PyEditor_Settings.h"
28 #include "PyEditor_Keywords.h"
37 \class PyEditor_Editor
38 \brief Widget to show / edit Python scripts.
43 \param parent parent widget
45 PyEditor_Editor::PyEditor_Editor( QWidget* parent )
46 : QPlainTextEdit( parent ),
47 myCompletionPolicy( Always )
49 myStdKeywords = new PyEditor_StandardKeywords( this );
50 myUserKeywords = new PyEditor_Keywords( this );
51 myUserKeywords->append( "print", 0, Qt::red );
53 // Set up line number area
54 myLineNumberArea = new PyEditor_LineNumberArea( this );
55 myLineNumberArea->setMouseTracking( true );
57 // Set up syntax highighter
58 mySyntaxHighlighter = new PyEditor_PyHighlighter( this->document(),
59 myStdKeywords, myUserKeywords );
62 PyEditor_Settings* settings = PyEditor_Settings::settings();
64 setSettings( *settings );
66 myCompleter = new PyEditor_Completer( this, myStdKeywords, myUserKeywords );
69 connect( this, SIGNAL( blockCountChanged( int ) ), this, SLOT( updateLineNumberAreaWidth( int ) ) );
70 connect( this, SIGNAL( updateRequest( QRect, int ) ), this, SLOT( updateLineNumberArea( QRect, int ) ) );
71 connect( this, SIGNAL( cursorPositionChanged() ), this, SLOT( updateHighlightCurrentLine() ) );
72 connect( this, SIGNAL( cursorPositionChanged() ), this, SLOT( matchParentheses() ) );
78 PyEditor_Editor::~PyEditor_Editor()
83 \brief Get editor settings.
84 \return settings object
86 const PyEditor_Settings& PyEditor_Editor::settings() const
92 \brief Set editor settings.
93 \param settings new settings
95 void PyEditor_Editor::setSettings( const PyEditor_Settings& settings )
97 mySettings.copyFrom( settings );
100 QFont aFont = font();
101 aFont.setFamily( mySettings.font().family() );
102 aFont.setPointSize( mySettings.font().pointSize() );
105 // Set line wrap mode
106 setLineWrapMode( mySettings.textWrapping() ? QPlainTextEdit::WidgetWidth : QPlainTextEdit::NoWrap );
108 // Center the cursor on screen
109 setCenterOnScroll( mySettings.centerCursorOnScroll() );
111 // Set size white spaces
112 setTabStopWidth( mySettings.tabSize() * 10 );
114 // Set completion policy
115 setCompletionPolicy( (CompletionPolicy)mySettings.completionPolicy() );
117 // Update current line highlight
118 updateHighlightCurrentLine();
120 // Update line numbers area
121 updateLineNumberAreaWidth( 0 );
123 mySyntaxHighlighter->rehighlight();
124 viewport()->update();
128 \brief Gets the current completion policy
129 \return completion policy
131 PyEditor_Editor::CompletionPolicy PyEditor_Editor::completionPolicy() const
133 return myCompletionPolicy;
137 \brief Sets the current completion policy
138 \param policy completion policy
140 void PyEditor_Editor::setCompletionPolicy( const CompletionPolicy& policy )
142 myCompletionPolicy = policy;
146 \brief Gets the all user keywords.
147 \param event key press event
148 \return keyword string list
150 QStringList PyEditor_Editor::keywords() const
152 return myUserKeywords->keywords();
156 \brief Add the user keywords.
157 \param kws keywords string list
158 \param type keywords type
159 \param color keywords color
161 void PyEditor_Editor::appendKeywords( const QStringList& kws, int type, const QColor& color )
163 myUserKeywords->append( kws, type, color );
167 \brief Remove the user keywords.
168 \param kws keywords string list
170 void PyEditor_Editor::removeKeywords( const QStringList& kws )
172 myUserKeywords->remove( kws );
176 Delete current selection contents.
178 void PyEditor_Editor::deleteSelected()
180 QTextCursor aCursor = textCursor();
181 if ( aCursor.hasSelection() )
182 aCursor.removeSelectedText();
183 setTextCursor( aCursor );
187 \brief Process key press event.
188 Reimplemented from QPlainTextEdit.
189 \param event key press event
191 void PyEditor_Editor::keyPressEvent( QKeyEvent* event )
193 if ( event->type() == QEvent::KeyPress )
195 int aKey = event->key();
196 Qt::KeyboardModifiers aCtrl = event->modifiers() & Qt::ControlModifier;
197 Qt::KeyboardModifiers aShift = event->modifiers() & Qt::ShiftModifier;
199 if ( aKey == Qt::Key_Tab || ( aKey == Qt::Key_Backtab || ( aKey == Qt::Key_Tab && aShift ) ) )
201 QTextCursor aCursor = textCursor();
202 aCursor.beginEditBlock();
203 tabIndentation( aKey == Qt::Key_Backtab );
204 aCursor.endEditBlock();
207 else if ( aKey == Qt::Key_Enter || aKey == Qt::Key_Return )
209 QTextCursor aCursor = textCursor();
210 aCursor.beginEditBlock();
211 if ( lineIndent() == 0 )
213 QPlainTextEdit::keyPressEvent( event );
215 aCursor.endEditBlock();
218 else if ( aKey == Qt::Key_Space && aCtrl && !aShift &&
219 ( completionPolicy() == Manual || completionPolicy() == Always ) )
221 myCompleter->perform();
224 else if ( event == QKeySequence::MoveToStartOfLine || event == QKeySequence::SelectStartOfLine )
226 QTextCursor aCursor = this->textCursor();
227 if ( QTextLayout* aLayout = aCursor.block().layout() )
229 if ( aLayout->lineForTextPosition( aCursor.position() - aCursor.block().position() ).lineNumber() == 0 )
231 handleHome( event == QKeySequence::SelectStartOfLine );
235 else if ( ( aKey == Qt::Key_Colon || ( aKey == Qt::Key_Space && !aCtrl && !aShift ) ) &&
236 !textCursor().hasSelection() )
238 QTextCursor aCursor = textCursor();
239 aCursor.movePosition( QTextCursor::StartOfBlock, QTextCursor::KeepAnchor );
241 QString aSelectedText = aCursor.selectedText();
242 int numSpaces = findFirstNonSpace( aSelectedText );
243 int amountChars = aSelectedText.size() - findFirstNonSpace( aSelectedText );
244 QString aLeadingText = aSelectedText.right( amountChars );
246 QStringList aReservedWords;
247 aReservedWords.append( "except" );
248 if ( aKey == Qt::Key_Colon )
250 aReservedWords.append( "else" );
251 aReservedWords.append( "finally" );
253 else if ( aKey == Qt::Key_Space )
255 aReservedWords.append( "elif" );
258 if ( aReservedWords.contains( aLeadingText ) )
260 QString aPreviousText = aCursor.block().previous().text();
261 int numSpacesPrevious = findFirstNonSpace( aPreviousText );
262 if ( numSpaces == numSpacesPrevious )
264 tabIndentation( true );
265 aCursor.movePosition( QTextCursor::EndOfBlock );
266 setTextCursor( aCursor );
269 QPlainTextEdit::keyPressEvent( event );
273 QPlainTextEdit::keyPressEvent( event );
279 \brief Handle resize event.
280 Reimplemented from QPlainTextEdit.
281 \param event resize event
283 void PyEditor_Editor::resizeEvent( QResizeEvent* event )
285 QPlainTextEdit::resizeEvent( event );
287 // Change size geometry of line number area
288 QRect aContentsRect = contentsRect();
289 myLineNumberArea->setGeometry( QRect( aContentsRect.left(),
291 lineNumberAreaWidth(),
292 aContentsRect.height() ) );
297 Reimplemented from QPlainTextEdit.
298 \param event paint event
300 void PyEditor_Editor::paintEvent( QPaintEvent* event )
302 QPlainTextEdit::paintEvent( event );
304 QTextBlock aBlock( firstVisibleBlock() );
305 QPointF anOffset( contentOffset() );
306 QPainter aPainter( this->viewport() );
308 int aTabSpaces = this->tabStopWidth() / 10;
310 // Visualization tab spaces
311 if ( mySettings.tabSpaceVisible() )
313 qreal aTop = blockBoundingGeometry( aBlock ).translated( anOffset ).top();
314 while ( aBlock.isValid() && aTop <= event->rect().bottom() )
316 if ( aBlock.isVisible() && blockBoundingGeometry( aBlock ).translated( anOffset ).toRect().intersects( event->rect() ) )
318 QString aText = aBlock.text();
319 if ( aText.contains( QRegExp( "\\w+" ) ) )
320 aText.remove( QRegExp( "(?!\\w+)\\s+$" ) );
324 while ( anIndex != -1 )
326 anIndex = aText.indexOf( QRegExp( QString( "^\\s{%1}" ).arg( aTabSpaces ) ), 0 );
329 aColumn = aColumn + aTabSpaces;
330 aText = aText.mid( aTabSpaces );
332 if ( aText.startsWith( ' ' ) )
334 QTextCursor aCursor( aBlock );
335 aCursor.setPosition( aBlock.position() + aColumn );
337 QRect aRect = cursorRect( aCursor );
338 aPainter.setPen( QPen( Qt::darkGray, 1, Qt::DotLine ) );
339 aPainter.drawLine( aRect.x() + 1, aRect.top(), aRect.x() + 1, aRect.bottom() );
344 aBlock = aBlock.next();
348 // Vertical edge line
349 if ( mySettings.verticalEdge() )
351 const QRect aRect = event->rect();
352 const QFont aFont = currentCharFormat().font();
353 int aNumberColumn = QFontMetrics( aFont ).averageCharWidth() * mySettings.numberColumns() + anOffset.x() + document()->documentMargin();
354 aPainter.setPen( QPen( Qt::lightGray, 1, Qt::SolidLine ) );
355 aPainter.drawLine( aNumberColumn, aRect.top(), aNumberColumn, aRect.bottom() );
359 void PyEditor_Editor::contextMenuEvent( QContextMenuEvent* event )
361 QMenu* menu = createStandardContextMenu();
362 emit customizeMenu( menu );
363 menu->exec( event->globalPos() );
368 \brief Indent and tab text.
369 \param isShift flag defines reverse tab direction
371 void PyEditor_Editor::tabIndentation( bool isShift )
373 QTextCursor aCursor = textCursor();
374 int aTabSpaces = this->tabStopWidth()/10;
376 if ( !aCursor.hasSelection() )
380 int N = aCursor.columnNumber() % aTabSpaces;
381 aCursor.insertText( QString( aTabSpaces - N, QLatin1Char( ' ' ) ) );
385 QTextBlock aCurrentBlock = document()->findBlock( aCursor.position() );
386 int anIndentPos = findFirstNonSpace( aCurrentBlock.text() );
387 aCursor.setPosition( aCurrentBlock.position() + anIndentPos );
388 setTextCursor( aCursor );
390 //if ( aCurrCursorColumnPos <= anIndentPos )
392 int aColumnPos = aCursor.columnNumber();
393 if ( aColumnPos != 0 )
395 int N = aCursor.columnNumber() % aTabSpaces;
396 if ( N == 0 ) N = aTabSpaces;
397 aCursor.movePosition( QTextCursor::Left, QTextCursor::KeepAnchor, N );
398 aCursor.removeSelectedText();
400 setTextCursor( aCursor );
406 indentSelection( isShift );
411 \brief Indent and tab selected text.
412 \param isShift flag defines reverse tab direction
414 void PyEditor_Editor::indentSelection( bool isShift )
416 QTextCursor aCursor = this->textCursor();
418 int aCursorStart = aCursor.selectionStart();
419 int aCursorEnd = aCursor.selectionEnd();
421 QTextBlock aStartBlock = document()->findBlock( aCursorStart );
422 QTextBlock anEndBlock = document()->findBlock( aCursorEnd - 1 ).next();
424 int aTabSpaces = this->tabStopWidth()/10;
426 for ( QTextBlock aBlock = aStartBlock; aBlock.isValid() && aBlock != anEndBlock; aBlock = aBlock.next() )
428 QString aText = aBlock.text();
429 int anIndentPos = findFirstNonSpace( aText );
430 int N = ( anIndentPos % aTabSpaces );
432 aCursor.setPosition( aBlock.position() + anIndentPos );
435 aCursor.insertText( QString( aTabSpaces - N, QLatin1Char( ' ' ) ) );
436 setTextCursor( aCursor );
440 int aColumnPos = aCursor.columnNumber();
441 if ( aColumnPos != 0 )
443 int blockN = aColumnPos % aTabSpaces;
444 if ( blockN == 0 ) blockN = aTabSpaces;
445 aCursor.movePosition( QTextCursor::Left, QTextCursor::KeepAnchor, blockN );
446 aCursor.removeSelectedText();
447 setTextCursor( aCursor );
452 // Reselect the selected lines
453 aCursor.setPosition( aStartBlock.position() );
454 aCursor.setPosition( anEndBlock.previous().position(), QTextCursor::KeepAnchor );
455 aCursor.movePosition( QTextCursor::EndOfBlock, QTextCursor::KeepAnchor );
456 setTextCursor( aCursor );
460 \brief Find first non white-space symbol in text.
461 \param text input text
462 \return index of first non white-space symbol
464 int PyEditor_Editor::findFirstNonSpace( const QString& text )
467 while ( i < text.size() )
469 if ( !text.at(i).isSpace() )
480 int PyEditor_Editor::lineIndent()
482 int aTabSpaces = this->tabStopWidth() / 10;
484 QTextCursor aCursor = textCursor();
485 aCursor.insertBlock();
486 setTextCursor( aCursor );
488 QTextBlock aCurrentBlock = aCursor.block();
489 if ( aCurrentBlock == document()->begin() )
492 QTextBlock aPreviousBlock = aCurrentBlock.previous();
494 QString aPreviousText;
497 if ( aPreviousBlock == document()->begin() )
499 aPreviousText = aPreviousBlock.text();
500 if ( aPreviousText.isEmpty() && aPreviousText.trimmed().isEmpty() )
505 // If the text of this block is not empty then break the loop.
506 aPreviousText = aPreviousBlock.text();
507 if ( !aPreviousText.isEmpty() && !aPreviousText.trimmed().isEmpty() )
510 aPreviousBlock = aPreviousBlock.previous();
513 int aTabIndentation = 0;
514 int anAmountIndentation = -1;
516 while ( i < aPreviousText.size() )
518 if ( !aPreviousText.at(i).isSpace() )
520 anAmountIndentation = findFirstNonSpace( aPreviousText );
530 if ( anAmountIndentation == -1 )
532 if ( aTabIndentation > 0 )
533 anAmountIndentation = aTabIndentation;
538 const QString aPreviousTrimmed = aPreviousText.trimmed();
539 if ( aPreviousTrimmed.endsWith( ":" ) )
541 anAmountIndentation += aTabSpaces;
545 if ( aPreviousTrimmed == "continue"
546 || aPreviousTrimmed == "break"
547 || aPreviousTrimmed == "pass"
548 || aPreviousTrimmed == "return"
549 || aPreviousTrimmed == "raise"
550 || aPreviousTrimmed.startsWith( "raise " )
551 || aPreviousTrimmed.startsWith( "return " ) )
552 anAmountIndentation -= aTabSpaces;
555 aCursor.insertText( QString( anAmountIndentation, QLatin1Char(' ') ) );
556 setTextCursor( aCursor );
562 \brief Set text cursor on home position.
563 \param isExtendLine \c true to keep current anchor position
565 void PyEditor_Editor::handleHome( bool isExtendLine )
567 QTextCursor aCursor = textCursor();
568 QTextCursor::MoveMode aMode = QTextCursor::MoveAnchor;
571 aMode = QTextCursor::KeepAnchor;
573 int anInitPos = aCursor.position();
574 int aBlockPos = aCursor.block().position();
576 QChar aCharacter = document()->characterAt( aBlockPos );
577 while ( aCharacter.category() == QChar::Separator_Space )
580 if ( aBlockPos == anInitPos )
582 aCharacter = document()->characterAt( aBlockPos );
585 if ( aBlockPos == anInitPos )
586 aBlockPos = aCursor.block().position();
588 aCursor.setPosition( aBlockPos, aMode );
589 setTextCursor( aCursor );
593 \brief Update current line highlighting.
595 void PyEditor_Editor::updateHighlightCurrentLine()
597 QList<QTextEdit::ExtraSelection> anExtraSelections;
598 if ( !isReadOnly() && mySettings.highlightCurrentLine() )
600 QTextEdit::ExtraSelection selection;
602 QColor lineColor = QColor( Qt::gray ).lighter( 155 );
604 selection.format.setBackground( lineColor );
605 selection.format.setProperty( QTextFormat::FullWidthSelection, QVariant( true ) );
606 selection.cursor = textCursor();
607 selection.cursor.clearSelection();
608 anExtraSelections.append( selection );
610 setExtraSelections( anExtraSelections );
614 \brief Draw linne number area.
615 \param event paint event
617 void PyEditor_Editor::lineNumberAreaPaintEvent( QPaintEvent* event )
619 QPainter aPainter( myLineNumberArea );
620 aPainter.fillRect( event->rect(), QColor( Qt::lightGray ).lighter( 125 ) );
622 QTextBlock aBlock = firstVisibleBlock();
623 int aBlockNumber = aBlock.blockNumber();
624 int aTop = (int)blockBoundingGeometry( aBlock ).translated( contentOffset() ).top();
625 int aBottom = aTop + (int)blockBoundingRect( aBlock ).height();
626 int aCurrentLine = document()->findBlock( textCursor().position() ).blockNumber();
628 QFont aFont = aPainter.font();
629 aPainter.setPen( this->palette().color( QPalette::Text ) );
631 while ( aBlock.isValid() && aTop <= event->rect().bottom() )
633 if ( aBlock.isVisible() && aBottom >= event->rect().top() )
635 if ( aBlockNumber == aCurrentLine )
637 aPainter.setPen( Qt::darkGray );
638 aFont.setBold( true );
639 aPainter.setFont( aFont );
643 aPainter.setPen( Qt::gray ) ;
644 aFont.setBold( false );
645 aPainter.setFont( aFont );
647 QString aNumber = QString::number( aBlockNumber + 1 );
648 aPainter.drawText( 0, aTop, myLineNumberArea->width(), fontMetrics().height(), Qt::AlignRight, aNumber );
651 aBlock = aBlock.next();
653 aBottom = aTop + (int)blockBoundingRect( aBlock ).height();
659 \brief Get with of line number area.
660 \return width of line number area
662 int PyEditor_Editor::lineNumberAreaWidth()
667 int aMaximum = qMax( 1, blockCount() );
668 while ( aMaximum >= 10 )
674 if ( mySettings.lineNumberArea() )
675 aSpace += 5 + fontMetrics().width( QLatin1Char( '9' ) ) * aDigits;
681 \brief Update width of the line number area.
682 \param newBlockCount (not used)
684 void PyEditor_Editor::updateLineNumberAreaWidth( int /*newBlockCount*/ )
686 setViewportMargins( lineNumberAreaWidth(), 0, 0, 0 );
690 \brief Update line number area (when editor viewport is scrolled).
691 \param rect area being updated
692 \param dy scroll factor
694 void PyEditor_Editor::updateLineNumberArea( const QRect& rect, int dy )
697 myLineNumberArea->scroll( 0, dy );
699 myLineNumberArea->update( 0, rect.y(), myLineNumberArea->width(), rect.height() );
701 if ( rect.contains( viewport()->rect() ) )
702 updateLineNumberAreaWidth( 0 );
706 \brief Manage parentheses.
708 void PyEditor_Editor::matchParentheses()
710 PyEditor_PyHighlighter::TextBlockData* data =
711 static_cast<PyEditor_PyHighlighter::TextBlockData*>( textCursor().block().userData() );
715 QVector<PyEditor_PyHighlighter::ParenthesisInfo*> infoEntries = data->parentheses();
717 int aPos = textCursor().block().position();
719 for ( int i = 0; i < infoEntries.size(); ++i )
721 PyEditor_PyHighlighter::ParenthesisInfo* info = infoEntries.at(i);
723 int currentColumnPosition = textCursor().columnNumber();
724 if ( info->position == currentColumnPosition - 1 && isLeftBrackets( info->character ) )
726 if ( matchLeftParenthesis( textCursor().block(), i + 1, 0 ) )
727 createParenthesisSelection( aPos + info->position );
729 else if ( info->position == currentColumnPosition && isLeftBrackets( info->character ) )
733 if ( matchLeftParenthesis( textCursor().block(), i + 1, 0 ) )
734 createParenthesisSelection( aPos + info->position );
737 else if ( info->position == currentColumnPosition - 1 && isRightBrackets( info->character ) )
739 if ( matchRightParenthesis( textCursor().block(), i - 1, 0 ) )
740 createParenthesisSelection( aPos + info->position );
743 else if ( info->position == currentColumnPosition && isRightBrackets( info->character ) )
745 if ( matchRightParenthesis( textCursor().block(), i - 1, 0 ) )
746 createParenthesisSelection( aPos + info->position );
753 \brief Match left brackets.
754 \param currentBlock text block
756 \param numLeftParentheses number of left parentheses
757 \return \c true if the left match
759 bool PyEditor_Editor::matchLeftParenthesis( const QTextBlock& currentBlock,
760 int idx, int numLeftParentheses )
762 PyEditor_PyHighlighter::TextBlockData* data =
763 static_cast<PyEditor_PyHighlighter::TextBlockData*>( currentBlock.userData() );
764 QVector<PyEditor_PyHighlighter::ParenthesisInfo*> infos = data->parentheses();
766 int docPos = currentBlock.position();
767 for ( ; idx < infos.size(); ++idx )
769 PyEditor_PyHighlighter::ParenthesisInfo* info = infos.at( idx );
771 if ( isLeftBrackets( info->character ) )
773 ++numLeftParentheses;
777 if ( isRightBrackets( info->character ) && numLeftParentheses == 0 )
779 createParenthesisSelection( docPos + info->position );
783 --numLeftParentheses;
786 QTextBlock nextBlock = currentBlock.next();
787 if ( nextBlock.isValid() )
788 return matchLeftParenthesis( nextBlock, 0, numLeftParentheses );
794 \brief Match right brackets.
795 \param currentBlock text block
797 \param numRightParentheses number of right parentheses
798 \return \c true if the right match
800 bool PyEditor_Editor::matchRightParenthesis( const QTextBlock& currentBlock,
801 int idx, int numRightParentheses )
803 PyEditor_PyHighlighter::TextBlockData* data = static_cast<PyEditor_PyHighlighter::TextBlockData*>( currentBlock.userData() );
804 QVector<PyEditor_PyHighlighter::ParenthesisInfo*> parentheses = data->parentheses();
806 int docPos = currentBlock.position();
807 for ( ; idx > -1 && parentheses.size() > 0; --idx )
809 PyEditor_PyHighlighter::ParenthesisInfo* info = parentheses.at( idx );
810 if ( isRightBrackets( info->character ) )
812 ++numRightParentheses;
815 if ( isLeftBrackets( info->character ) && numRightParentheses == 0 )
817 createParenthesisSelection( docPos + info->position );
821 --numRightParentheses;
824 QTextBlock prevBlock = currentBlock.previous();
825 if ( prevBlock.isValid() )
827 PyEditor_PyHighlighter::TextBlockData* data = static_cast<PyEditor_PyHighlighter::TextBlockData*>( prevBlock.userData() );
828 QVector<PyEditor_PyHighlighter::ParenthesisInfo*> parentheses = data->parentheses();
829 return matchRightParenthesis( prevBlock, parentheses.size() - 1, numRightParentheses );
836 \brief Create brackets selection.
837 \param position cursor position
839 void PyEditor_Editor::createParenthesisSelection( int position )
841 QList<QTextEdit::ExtraSelection> selections = extraSelections();
843 QTextEdit::ExtraSelection selection;
845 QTextCharFormat format = selection.format;
846 format.setForeground( Qt::red );
847 format.setBackground( Qt::white );
848 selection.format = format;
850 QTextCursor cursor = textCursor();
851 cursor.setPosition( position );
852 cursor.movePosition( QTextCursor::NextCharacter, QTextCursor::KeepAnchor );
853 selection.cursor = cursor;
855 selections.append( selection );
856 setExtraSelections( selections );
860 \brief Check if symbol is a left bracket.
861 \param symbol text symbol
862 \return \c true if symbol is any left bracket
864 bool PyEditor_Editor::isLeftBrackets( QChar symbol )
866 return symbol == '(' || symbol == '{' || symbol == '[';
870 \brief Check if symbol is a right bracket.
871 \param symbol text symbol
872 \return \c true if symbol is any right bracket
874 bool PyEditor_Editor::isRightBrackets( QChar symbol )
876 return symbol == ')' || symbol == '}' || symbol == ']';
880 \brief Append new paragraph to the end of the editor's text.
881 \param text paragraph text
883 void PyEditor_Editor::append( const QString& text )
885 appendPlainText( text );
889 \brief Set text to the editor.
892 void PyEditor_Editor::setText( const QString& text )
894 setPlainText( text );
898 \brief Get current editor's content.
901 QString PyEditor_Editor::text() const
903 return toPlainText();
907 \brief Get user keywords dictionary.
908 \return keywords dictionary
910 PyEditor_Keywords* PyEditor_Editor::userKeywords() const
912 return myUserKeywords;
916 \brief Get standard keywords dictionary.
917 \return keywords dictionary
919 PyEditor_Keywords* PyEditor_Editor::standardKeywords() const
921 return myStdKeywords;