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"
36 \class PyEditor_Editor
37 \brief Widget to show / edit Python scripts.
42 \param parent parent widget
44 PyEditor_Editor::PyEditor_Editor( QWidget* parent )
45 : QPlainTextEdit( parent ),
46 myCompletionPolicy( Always )
48 myStdKeywords = new PyEditor_StandardKeywords( this );
49 myUserKeywords = new PyEditor_Keywords( this );
50 myUserKeywords->append( "print", 0, Qt::red );
52 // Set up line number area
53 myLineNumberArea = new PyEditor_LineNumberArea( this );
54 myLineNumberArea->setMouseTracking( true );
56 // Set up syntax highighter
57 mySyntaxHighlighter = new PyEditor_PyHighlighter( this->document(),
58 myStdKeywords, myUserKeywords );
61 PyEditor_Settings* settings = PyEditor_Settings::settings();
63 setSettings( *settings );
65 myCompleter = new PyEditor_Completer( this, myStdKeywords, myUserKeywords );
68 connect( this, SIGNAL( blockCountChanged( int ) ), this, SLOT( updateLineNumberAreaWidth( int ) ) );
69 connect( this, SIGNAL( updateRequest( QRect, int ) ), this, SLOT( updateLineNumberArea( QRect, int ) ) );
70 connect( this, SIGNAL( cursorPositionChanged() ), this, SLOT( updateHighlightCurrentLine() ) );
71 connect( this, SIGNAL( cursorPositionChanged() ), this, SLOT( matchParentheses() ) );
77 PyEditor_Editor::~PyEditor_Editor()
82 \brief Get editor settings.
83 \return settings object
85 const PyEditor_Settings& PyEditor_Editor::settings() const
91 \brief Set editor settings.
92 \param settings new settings
94 void PyEditor_Editor::setSettings( const PyEditor_Settings& settings )
96 mySettings.copyFrom( settings );
100 aFont.setFamily( mySettings.font().family() );
101 aFont.setPointSize( mySettings.font().pointSize() );
104 // Set line wrap mode
105 setLineWrapMode( mySettings.textWrapping() ? QPlainTextEdit::WidgetWidth : QPlainTextEdit::NoWrap );
107 // Center the cursor on screen
108 setCenterOnScroll( mySettings.centerCursorOnScroll() );
110 // Set size white spaces
111 setTabStopWidth( mySettings.tabSize() * 10 );
113 // Set completion policy
114 setCompletionPolicy( (CompletionPolicy)mySettings.completionPolicy() );
116 // Update current line highlight
117 updateHighlightCurrentLine();
119 // Update line numbers area
120 updateLineNumberAreaWidth( 0 );
122 mySyntaxHighlighter->rehighlight();
123 viewport()->update();
127 \brief Gets the current completion policy
128 \return completion policy
130 PyEditor_Editor::CompletionPolicy PyEditor_Editor::completionPolicy() const
132 return myCompletionPolicy;
136 \brief Sets the current completion policy
137 \param policy completion policy
139 void PyEditor_Editor::setCompletionPolicy( const CompletionPolicy& policy )
141 myCompletionPolicy = policy;
145 \brief Gets the all user keywords.
146 \param event key press event
147 \return keyword string list
149 QStringList PyEditor_Editor::keywords() const
151 return myUserKeywords->keywords();
155 \brief Add the user keywords.
156 \param kws keywords string list
157 \param type keywords type
158 \param color keywords color
160 void PyEditor_Editor::appendKeywords( const QStringList& kws, int type, const QColor& color )
162 myUserKeywords->append( kws, type, color );
166 \brief Remove the user keywords.
167 \param kws keywords string list
169 void PyEditor_Editor::removeKeywords( const QStringList& kws )
171 myUserKeywords->remove( kws );
175 Delete current selection contents.
177 void PyEditor_Editor::deleteSelected()
179 QTextCursor aCursor = textCursor();
180 if ( aCursor.hasSelection() )
181 aCursor.removeSelectedText();
182 setTextCursor( aCursor );
186 \brief Process key press event.
187 Reimplemented from QPlainTextEdit.
188 \param event key press event
190 void PyEditor_Editor::keyPressEvent( QKeyEvent* event )
192 if ( event->type() == QEvent::KeyPress )
194 int aKey = event->key();
195 Qt::KeyboardModifiers aCtrl = event->modifiers() & Qt::ControlModifier;
196 Qt::KeyboardModifiers aShift = event->modifiers() & Qt::ShiftModifier;
198 if ( aKey == Qt::Key_Tab || ( aKey == Qt::Key_Backtab || ( aKey == Qt::Key_Tab && aShift ) ) )
200 QTextCursor aCursor = textCursor();
201 aCursor.beginEditBlock();
202 tabIndentation( aKey == Qt::Key_Backtab );
203 aCursor.endEditBlock();
206 else if ( aKey == Qt::Key_Enter || aKey == Qt::Key_Return )
208 QTextCursor aCursor = textCursor();
209 aCursor.beginEditBlock();
210 if ( lineIndent() == 0 )
212 QPlainTextEdit::keyPressEvent( event );
214 aCursor.endEditBlock();
217 else if ( aKey == Qt::Key_Space && aCtrl && !aShift &&
218 ( completionPolicy() == Manual || completionPolicy() == Always ) )
220 myCompleter->perform();
223 else if ( event == QKeySequence::MoveToStartOfLine || event == QKeySequence::SelectStartOfLine )
225 QTextCursor aCursor = this->textCursor();
226 if ( QTextLayout* aLayout = aCursor.block().layout() )
228 if ( aLayout->lineForTextPosition( aCursor.position() - aCursor.block().position() ).lineNumber() == 0 )
230 handleHome( event == QKeySequence::SelectStartOfLine );
234 else if ( ( aKey == Qt::Key_Colon || ( aKey == Qt::Key_Space && !aCtrl && !aShift ) ) &&
235 !textCursor().hasSelection() )
237 QTextCursor aCursor = textCursor();
238 aCursor.movePosition( QTextCursor::StartOfBlock, QTextCursor::KeepAnchor );
240 QString aSelectedText = aCursor.selectedText();
241 int numSpaces = findFirstNonSpace( aSelectedText );
242 int amountChars = aSelectedText.size() - findFirstNonSpace( aSelectedText );
243 QString aLeadingText = aSelectedText.right( amountChars );
245 QStringList aReservedWords;
246 aReservedWords.append( "except" );
247 if ( aKey == Qt::Key_Colon )
249 aReservedWords.append( "else" );
250 aReservedWords.append( "finally" );
252 else if ( aKey == Qt::Key_Space )
254 aReservedWords.append( "elif" );
257 if ( aReservedWords.contains( aLeadingText ) )
259 QString aPreviousText = aCursor.block().previous().text();
260 int numSpacesPrevious = findFirstNonSpace( aPreviousText );
261 if ( numSpaces == numSpacesPrevious )
263 tabIndentation( true );
264 aCursor.movePosition( QTextCursor::EndOfBlock );
265 setTextCursor( aCursor );
268 QPlainTextEdit::keyPressEvent( event );
272 QPlainTextEdit::keyPressEvent( event );
278 \brief Handle resize event.
279 Reimplemented from QPlainTextEdit.
280 \param event resize event
282 void PyEditor_Editor::resizeEvent( QResizeEvent* event )
284 QPlainTextEdit::resizeEvent( event );
286 // Change size geometry of line number area
287 QRect aContentsRect = contentsRect();
288 myLineNumberArea->setGeometry( QRect( aContentsRect.left(),
290 lineNumberAreaWidth(),
291 aContentsRect.height() ) );
296 Reimplemented from QPlainTextEdit.
297 \param event paint event
299 void PyEditor_Editor::paintEvent( QPaintEvent* event )
301 QPlainTextEdit::paintEvent( event );
303 QTextBlock aBlock( firstVisibleBlock() );
304 QPointF anOffset( contentOffset() );
305 QPainter aPainter( this->viewport() );
307 int aTabSpaces = this->tabStopWidth() / 10;
309 // Visualization tab spaces
310 if ( mySettings.tabSpaceVisible() )
312 qreal aTop = blockBoundingGeometry( aBlock ).translated( anOffset ).top();
313 while ( aBlock.isValid() && aTop <= event->rect().bottom() )
315 if ( aBlock.isVisible() && blockBoundingGeometry( aBlock ).translated( anOffset ).toRect().intersects( event->rect() ) )
317 QString aText = aBlock.text();
318 if ( aText.contains( QRegExp( "\\w+" ) ) )
319 aText.remove( QRegExp( "(?!\\w+)\\s+$" ) );
323 while ( anIndex != -1 )
325 anIndex = aText.indexOf( QRegExp( QString( "^\\s{%1}" ).arg( aTabSpaces ) ), 0 );
328 aColumn = aColumn + aTabSpaces;
329 aText = aText.mid( aTabSpaces );
331 if ( aText.startsWith( ' ' ) )
333 QTextCursor aCursor( aBlock );
334 aCursor.setPosition( aBlock.position() + aColumn );
336 QRect aRect = cursorRect( aCursor );
337 aPainter.setPen( QPen( Qt::darkGray, 1, Qt::DotLine ) );
338 aPainter.drawLine( aRect.x() + 1, aRect.top(), aRect.x() + 1, aRect.bottom() );
343 aBlock = aBlock.next();
347 // Vertical edge line
348 if ( mySettings.verticalEdge() )
350 const QRect aRect = event->rect();
351 const QFont aFont = currentCharFormat().font();
352 int aNumberColumn = QFontMetrics( aFont ).averageCharWidth() * mySettings.numberColumns() + anOffset.x() + document()->documentMargin();
353 aPainter.setPen( QPen( Qt::lightGray, 1, Qt::SolidLine ) );
354 aPainter.drawLine( aNumberColumn, aRect.top(), aNumberColumn, aRect.bottom() );
359 \brief Indent and tab text.
360 \param isShift flag defines reverse tab direction
362 void PyEditor_Editor::tabIndentation( bool isShift )
364 QTextCursor aCursor = textCursor();
365 int aTabSpaces = this->tabStopWidth()/10;
367 if ( !aCursor.hasSelection() )
371 int N = aCursor.columnNumber() % aTabSpaces;
372 aCursor.insertText( QString( aTabSpaces - N, QLatin1Char( ' ' ) ) );
376 QTextBlock aCurrentBlock = document()->findBlock( aCursor.position() );
377 int anIndentPos = findFirstNonSpace( aCurrentBlock.text() );
378 aCursor.setPosition( aCurrentBlock.position() + anIndentPos );
379 setTextCursor( aCursor );
381 //if ( aCurrCursorColumnPos <= anIndentPos )
383 int aColumnPos = aCursor.columnNumber();
384 if ( aColumnPos != 0 )
386 int N = aCursor.columnNumber() % aTabSpaces;
387 if ( N == 0 ) N = aTabSpaces;
388 aCursor.movePosition( QTextCursor::Left, QTextCursor::KeepAnchor, N );
389 aCursor.removeSelectedText();
391 setTextCursor( aCursor );
397 indentSelection( isShift );
402 \brief Indent and tab selected text.
403 \param isShift flag defines reverse tab direction
405 void PyEditor_Editor::indentSelection( bool isShift )
407 QTextCursor aCursor = this->textCursor();
409 int aCursorStart = aCursor.selectionStart();
410 int aCursorEnd = aCursor.selectionEnd();
412 QTextBlock aStartBlock = document()->findBlock( aCursorStart );
413 QTextBlock anEndBlock = document()->findBlock( aCursorEnd - 1 ).next();
415 int aTabSpaces = this->tabStopWidth()/10;
417 for ( QTextBlock aBlock = aStartBlock; aBlock.isValid() && aBlock != anEndBlock; aBlock = aBlock.next() )
419 QString aText = aBlock.text();
420 int anIndentPos = findFirstNonSpace( aText );
421 int N = ( anIndentPos % aTabSpaces );
423 aCursor.setPosition( aBlock.position() + anIndentPos );
426 aCursor.insertText( QString( aTabSpaces - N, QLatin1Char( ' ' ) ) );
427 setTextCursor( aCursor );
431 int aColumnPos = aCursor.columnNumber();
432 if ( aColumnPos != 0 )
434 int blockN = aColumnPos % aTabSpaces;
435 if ( blockN == 0 ) blockN = aTabSpaces;
436 aCursor.movePosition( QTextCursor::Left, QTextCursor::KeepAnchor, blockN );
437 aCursor.removeSelectedText();
438 setTextCursor( aCursor );
443 // Reselect the selected lines
444 aCursor.setPosition( aStartBlock.position() );
445 aCursor.setPosition( anEndBlock.previous().position(), QTextCursor::KeepAnchor );
446 aCursor.movePosition( QTextCursor::EndOfBlock, QTextCursor::KeepAnchor );
447 setTextCursor( aCursor );
451 \brief Find first non white-space symbol in text.
452 \param text input text
453 \return index of first non white-space symbol
455 int PyEditor_Editor::findFirstNonSpace( const QString& text )
458 while ( i < text.size() )
460 if ( !text.at(i).isSpace() )
471 int PyEditor_Editor::lineIndent()
473 int aTabSpaces = this->tabStopWidth() / 10;
475 QTextCursor aCursor = textCursor();
476 aCursor.insertBlock();
477 setTextCursor( aCursor );
479 QTextBlock aCurrentBlock = aCursor.block();
480 if ( aCurrentBlock == document()->begin() )
483 QTextBlock aPreviousBlock = aCurrentBlock.previous();
485 QString aPreviousText;
488 if ( aPreviousBlock == document()->begin() )
490 aPreviousText = aPreviousBlock.text();
491 if ( aPreviousText.isEmpty() && aPreviousText.trimmed().isEmpty() )
496 // If the text of this block is not empty then break the loop.
497 aPreviousText = aPreviousBlock.text();
498 if ( !aPreviousText.isEmpty() && !aPreviousText.trimmed().isEmpty() )
501 aPreviousBlock = aPreviousBlock.previous();
504 int aTabIndentation = 0;
505 int anAmountIndentation = -1;
507 while ( i < aPreviousText.size() )
509 if ( !aPreviousText.at(i).isSpace() )
511 anAmountIndentation = findFirstNonSpace( aPreviousText );
521 if ( anAmountIndentation == -1 )
523 if ( aTabIndentation > 0 )
524 anAmountIndentation = aTabIndentation;
529 const QString aPreviousTrimmed = aPreviousText.trimmed();
530 if ( aPreviousTrimmed.endsWith( ":" ) )
532 anAmountIndentation += aTabSpaces;
536 if ( aPreviousTrimmed == "continue"
537 || aPreviousTrimmed == "break"
538 || aPreviousTrimmed == "pass"
539 || aPreviousTrimmed == "return"
540 || aPreviousTrimmed == "raise"
541 || aPreviousTrimmed.startsWith( "raise " )
542 || aPreviousTrimmed.startsWith( "return " ) )
543 anAmountIndentation -= aTabSpaces;
546 aCursor.insertText( QString( anAmountIndentation, QLatin1Char(' ') ) );
547 setTextCursor( aCursor );
553 \brief Set text cursor on home position.
554 \param isExtendLine \c true to keep current anchor position
556 void PyEditor_Editor::handleHome( bool isExtendLine )
558 QTextCursor aCursor = textCursor();
559 QTextCursor::MoveMode aMode = QTextCursor::MoveAnchor;
562 aMode = QTextCursor::KeepAnchor;
564 int anInitPos = aCursor.position();
565 int aBlockPos = aCursor.block().position();
567 QChar aCharacter = document()->characterAt( aBlockPos );
568 while ( aCharacter.category() == QChar::Separator_Space )
571 if ( aBlockPos == anInitPos )
573 aCharacter = document()->characterAt( aBlockPos );
576 if ( aBlockPos == anInitPos )
577 aBlockPos = aCursor.block().position();
579 aCursor.setPosition( aBlockPos, aMode );
580 setTextCursor( aCursor );
584 \brief Update current line highlighting.
586 void PyEditor_Editor::updateHighlightCurrentLine()
588 QList<QTextEdit::ExtraSelection> anExtraSelections;
589 if ( !isReadOnly() && mySettings.highlightCurrentLine() )
591 QTextEdit::ExtraSelection selection;
593 QColor lineColor = QColor( Qt::gray ).lighter( 155 );
595 selection.format.setBackground( lineColor );
596 selection.format.setProperty( QTextFormat::FullWidthSelection, QVariant( true ) );
597 selection.cursor = textCursor();
598 selection.cursor.clearSelection();
599 anExtraSelections.append( selection );
601 setExtraSelections( anExtraSelections );
605 \brief Draw linne number area.
606 \param event paint event
608 void PyEditor_Editor::lineNumberAreaPaintEvent( QPaintEvent* event )
610 QPainter aPainter( myLineNumberArea );
611 aPainter.fillRect( event->rect(), QColor( Qt::lightGray ).lighter( 125 ) );
613 QTextBlock aBlock = firstVisibleBlock();
614 int aBlockNumber = aBlock.blockNumber();
615 int aTop = (int)blockBoundingGeometry( aBlock ).translated( contentOffset() ).top();
616 int aBottom = aTop + (int)blockBoundingRect( aBlock ).height();
617 int aCurrentLine = document()->findBlock( textCursor().position() ).blockNumber();
619 QFont aFont = aPainter.font();
620 aPainter.setPen( this->palette().color( QPalette::Text ) );
622 while ( aBlock.isValid() && aTop <= event->rect().bottom() )
624 if ( aBlock.isVisible() && aBottom >= event->rect().top() )
626 if ( aBlockNumber == aCurrentLine )
628 aPainter.setPen( Qt::darkGray );
629 aFont.setBold( true );
630 aPainter.setFont( aFont );
634 aPainter.setPen( Qt::gray ) ;
635 aFont.setBold( false );
636 aPainter.setFont( aFont );
638 QString aNumber = QString::number( aBlockNumber + 1 );
639 aPainter.drawText( 0, aTop, myLineNumberArea->width(), fontMetrics().height(), Qt::AlignRight, aNumber );
642 aBlock = aBlock.next();
644 aBottom = aTop + (int)blockBoundingRect( aBlock ).height();
650 \brief Get with of line number area.
651 \return width of line number area
653 int PyEditor_Editor::lineNumberAreaWidth()
658 int aMaximum = qMax( 1, blockCount() );
659 while ( aMaximum >= 10 )
665 if ( mySettings.lineNumberArea() )
666 aSpace += 5 + fontMetrics().width( QLatin1Char( '9' ) ) * aDigits;
672 \brief Update width of the line number area.
673 \param newBlockCount (not used)
675 void PyEditor_Editor::updateLineNumberAreaWidth( int /*newBlockCount*/ )
677 setViewportMargins( lineNumberAreaWidth(), 0, 0, 0 );
681 \brief Update line number area (when editor viewport is scrolled).
682 \param rect area being updated
683 \param dy scroll factor
685 void PyEditor_Editor::updateLineNumberArea( const QRect& rect, int dy )
688 myLineNumberArea->scroll( 0, dy );
690 myLineNumberArea->update( 0, rect.y(), myLineNumberArea->width(), rect.height() );
692 if ( rect.contains( viewport()->rect() ) )
693 updateLineNumberAreaWidth( 0 );
697 \brief Manage parentheses.
699 void PyEditor_Editor::matchParentheses()
701 PyEditor_PyHighlighter::TextBlockData* data =
702 static_cast<PyEditor_PyHighlighter::TextBlockData*>( textCursor().block().userData() );
706 QVector<PyEditor_PyHighlighter::ParenthesisInfo*> infoEntries = data->parentheses();
708 int aPos = textCursor().block().position();
710 for ( int i = 0; i < infoEntries.size(); ++i )
712 PyEditor_PyHighlighter::ParenthesisInfo* info = infoEntries.at(i);
714 int currentColumnPosition = textCursor().columnNumber();
715 if ( info->position == currentColumnPosition - 1 && isLeftBrackets( info->character ) )
717 if ( matchLeftParenthesis( textCursor().block(), i + 1, 0 ) )
718 createParenthesisSelection( aPos + info->position );
720 else if ( info->position == currentColumnPosition && isLeftBrackets( info->character ) )
724 if ( matchLeftParenthesis( textCursor().block(), i + 1, 0 ) )
725 createParenthesisSelection( aPos + info->position );
728 else if ( info->position == currentColumnPosition - 1 && isRightBrackets( info->character ) )
730 if ( matchRightParenthesis( textCursor().block(), i - 1, 0 ) )
731 createParenthesisSelection( aPos + info->position );
734 else if ( info->position == currentColumnPosition && isRightBrackets( info->character ) )
736 if ( matchRightParenthesis( textCursor().block(), i - 1, 0 ) )
737 createParenthesisSelection( aPos + info->position );
744 \brief Match left brackets.
745 \param currentBlock text block
747 \param numLeftParentheses number of left parentheses
748 \return \c true if the left match
750 bool PyEditor_Editor::matchLeftParenthesis( const QTextBlock& currentBlock,
751 int idx, int numLeftParentheses )
753 PyEditor_PyHighlighter::TextBlockData* data =
754 static_cast<PyEditor_PyHighlighter::TextBlockData*>( currentBlock.userData() );
755 QVector<PyEditor_PyHighlighter::ParenthesisInfo*> infos = data->parentheses();
757 int docPos = currentBlock.position();
758 for ( ; idx < infos.size(); ++idx )
760 PyEditor_PyHighlighter::ParenthesisInfo* info = infos.at( idx );
762 if ( isLeftBrackets( info->character ) )
764 ++numLeftParentheses;
768 if ( isRightBrackets( info->character ) && numLeftParentheses == 0 )
770 createParenthesisSelection( docPos + info->position );
774 --numLeftParentheses;
777 QTextBlock nextBlock = currentBlock.next();
778 if ( nextBlock.isValid() )
779 return matchLeftParenthesis( nextBlock, 0, numLeftParentheses );
785 \brief Match right brackets.
786 \param currentBlock text block
788 \param numRightParentheses number of right parentheses
789 \return \c true if the right match
791 bool PyEditor_Editor::matchRightParenthesis( const QTextBlock& currentBlock,
792 int idx, int numRightParentheses )
794 PyEditor_PyHighlighter::TextBlockData* data = static_cast<PyEditor_PyHighlighter::TextBlockData*>( currentBlock.userData() );
795 QVector<PyEditor_PyHighlighter::ParenthesisInfo*> parentheses = data->parentheses();
797 int docPos = currentBlock.position();
798 for ( ; idx > -1 && parentheses.size() > 0; --idx )
800 PyEditor_PyHighlighter::ParenthesisInfo* info = parentheses.at( idx );
801 if ( isRightBrackets( info->character ) )
803 ++numRightParentheses;
806 if ( isLeftBrackets( info->character ) && numRightParentheses == 0 )
808 createParenthesisSelection( docPos + info->position );
812 --numRightParentheses;
815 QTextBlock prevBlock = currentBlock.previous();
816 if ( prevBlock.isValid() )
818 PyEditor_PyHighlighter::TextBlockData* data = static_cast<PyEditor_PyHighlighter::TextBlockData*>( prevBlock.userData() );
819 QVector<PyEditor_PyHighlighter::ParenthesisInfo*> parentheses = data->parentheses();
820 return matchRightParenthesis( prevBlock, parentheses.size() - 1, numRightParentheses );
827 \brief Create brackets selection.
828 \param position cursor position
830 void PyEditor_Editor::createParenthesisSelection( int position )
832 QList<QTextEdit::ExtraSelection> selections = extraSelections();
834 QTextEdit::ExtraSelection selection;
836 QTextCharFormat format = selection.format;
837 format.setForeground( Qt::red );
838 format.setBackground( Qt::white );
839 selection.format = format;
841 QTextCursor cursor = textCursor();
842 cursor.setPosition( position );
843 cursor.movePosition( QTextCursor::NextCharacter, QTextCursor::KeepAnchor );
844 selection.cursor = cursor;
846 selections.append( selection );
847 setExtraSelections( selections );
851 \brief Check if symbol is a left bracket.
852 \param symbol text symbol
853 \return \c true if symbol is any left bracket
855 bool PyEditor_Editor::isLeftBrackets( QChar symbol )
857 return symbol == '(' || symbol == '{' || symbol == '[';
861 \brief Check if symbol is a right bracket.
862 \param symbol text symbol
863 \return \c true if symbol is any right bracket
865 bool PyEditor_Editor::isRightBrackets( QChar symbol )
867 return symbol == ')' || symbol == '}' || symbol == ']';
871 \brief Append new paragraph to the end of the editor's text.
872 \param text paragraph text
874 void PyEditor_Editor::append( const QString& text )
876 appendPlainText( text );
880 \brief Set text to the editor.
883 void PyEditor_Editor::setText( const QString& text )
885 setPlainText( text );
889 \brief Get current editor's content.
892 QString PyEditor_Editor::text() const
894 return toPlainText();
898 \brief Get user keywords dictionary.
899 \return keywords dictionary
901 PyEditor_Keywords* PyEditor_Editor::userKeywords() const
903 return myUserKeywords;
907 \brief Get standard keywords dictionary.
908 \return keywords dictionary
910 PyEditor_Keywords* PyEditor_Editor::standardKeywords() const
912 return myStdKeywords;