src/gui/text/qsyntaxhighlighter.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qsyntaxhighlighter.h"
       
    43 
       
    44 #ifndef QT_NO_SYNTAXHIGHLIGHTER
       
    45 #include <private/qobject_p.h>
       
    46 #include <qtextdocument.h>
       
    47 #include <private/qtextdocument_p.h>
       
    48 #include <qtextlayout.h>
       
    49 #include <qpointer.h>
       
    50 #include <qtextobject.h>
       
    51 #include <qtextcursor.h>
       
    52 #include <qdebug.h>
       
    53 #include <qtextedit.h>
       
    54 #include <qtimer.h>
       
    55 
       
    56 QT_BEGIN_NAMESPACE
       
    57 
       
    58 class QSyntaxHighlighterPrivate : public QObjectPrivate
       
    59 {
       
    60     Q_DECLARE_PUBLIC(QSyntaxHighlighter)
       
    61 public:
       
    62     inline QSyntaxHighlighterPrivate() : rehighlightPending(false) {}
       
    63 
       
    64     QPointer<QTextDocument> doc;
       
    65 
       
    66     void _q_reformatBlocks(int from, int charsRemoved, int charsAdded);
       
    67     void reformatBlock(QTextBlock block);
       
    68     
       
    69     inline void rehighlight(QTextCursor &cursor, QTextCursor::MoveOperation operation) {
       
    70         QObject::disconnect(doc, SIGNAL(contentsChange(int,int,int)),
       
    71                             q_func(), SLOT(_q_reformatBlocks(int,int,int)));
       
    72         cursor.beginEditBlock();
       
    73         int from = cursor.position();
       
    74         cursor.movePosition(operation);
       
    75         _q_reformatBlocks(from, 0, cursor.position() - from);
       
    76         cursor.endEditBlock();
       
    77         QObject::connect(doc, SIGNAL(contentsChange(int,int,int)),
       
    78                          q_func(), SLOT(_q_reformatBlocks(int,int,int)));
       
    79     }
       
    80 
       
    81     inline void _q_delayedRehighlight() {
       
    82         if (!rehighlightPending)
       
    83             return;
       
    84         rehighlightPending = false;
       
    85         q_func()->rehighlight();
       
    86         return;
       
    87     }
       
    88 
       
    89     void applyFormatChanges();
       
    90     QVector<QTextCharFormat> formatChanges;
       
    91     QTextBlock currentBlock;
       
    92     bool rehighlightPending;
       
    93 };
       
    94 
       
    95 void QSyntaxHighlighterPrivate::applyFormatChanges()
       
    96 {
       
    97     QTextLayout *layout = currentBlock.layout();
       
    98 
       
    99     QList<QTextLayout::FormatRange> ranges = layout->additionalFormats();
       
   100 
       
   101     const int preeditAreaStart = layout->preeditAreaPosition();
       
   102     const int preeditAreaLength = layout->preeditAreaText().length();
       
   103 
       
   104     QList<QTextLayout::FormatRange>::Iterator it = ranges.begin();
       
   105     while (it != ranges.end()) {
       
   106         if (it->start >= preeditAreaStart
       
   107             && it->start + it->length <= preeditAreaStart + preeditAreaLength)
       
   108             ++it;
       
   109         else
       
   110             it = ranges.erase(it);
       
   111     }
       
   112 
       
   113     QTextCharFormat emptyFormat;
       
   114 
       
   115     QTextLayout::FormatRange r;
       
   116     r.start = r.length = -1;
       
   117 
       
   118     int i = 0;
       
   119     while (i < formatChanges.count()) {
       
   120 
       
   121         while (i < formatChanges.count() && formatChanges.at(i) == emptyFormat)
       
   122             ++i;
       
   123 
       
   124         if (i >= formatChanges.count())
       
   125             break;
       
   126 
       
   127         r.start = i;
       
   128         r.format = formatChanges.at(i);
       
   129 
       
   130         while (i < formatChanges.count() && formatChanges.at(i) == r.format)
       
   131             ++i;
       
   132 
       
   133         if (i >= formatChanges.count())
       
   134             break;
       
   135 
       
   136         r.length = i - r.start;
       
   137 
       
   138         if (r.start >= preeditAreaStart) {
       
   139             r.start += preeditAreaLength;
       
   140         } else if (r.start + r.length >= preeditAreaStart) {
       
   141             r.length += preeditAreaLength;
       
   142         }
       
   143 
       
   144         ranges << r;
       
   145         r.start = r.length = -1;
       
   146     }
       
   147 
       
   148     if (r.start != -1) {
       
   149         r.length = formatChanges.count() - r.start;
       
   150 
       
   151         if (r.start >= preeditAreaStart) {
       
   152             r.start += preeditAreaLength;
       
   153         } else if (r.start + r.length >= preeditAreaStart) {
       
   154             r.length += preeditAreaLength;
       
   155         }
       
   156 
       
   157         ranges << r;
       
   158     }
       
   159 
       
   160     layout->setAdditionalFormats(ranges);
       
   161 }
       
   162 
       
   163 void QSyntaxHighlighterPrivate::_q_reformatBlocks(int from, int charsRemoved, int charsAdded)
       
   164 {
       
   165     Q_UNUSED(charsRemoved);
       
   166     rehighlightPending = false;
       
   167 
       
   168     QTextBlock block = doc->findBlock(from);
       
   169     if (!block.isValid())
       
   170         return;
       
   171 
       
   172     int endPosition;
       
   173     QTextBlock lastBlock = doc->findBlock(from + charsAdded + (charsRemoved > 0 ? 1 : 0));
       
   174     if (lastBlock.isValid())
       
   175         endPosition = lastBlock.position() + lastBlock.length();
       
   176     else
       
   177         endPosition = doc->docHandle()->length();
       
   178 
       
   179     bool forceHighlightOfNextBlock = false;
       
   180 
       
   181     while (block.isValid() && (block.position() < endPosition || forceHighlightOfNextBlock)) {
       
   182         const int stateBeforeHighlight = block.userState();
       
   183 
       
   184         reformatBlock(block);
       
   185 
       
   186         forceHighlightOfNextBlock = (block.userState() != stateBeforeHighlight);
       
   187 
       
   188         block = block.next();
       
   189     }
       
   190 
       
   191     formatChanges.clear();
       
   192 }
       
   193 
       
   194 void QSyntaxHighlighterPrivate::reformatBlock(QTextBlock block)
       
   195 {
       
   196     Q_Q(QSyntaxHighlighter);
       
   197 
       
   198     Q_ASSERT_X(!currentBlock.isValid(), "QSyntaxHighlighter::reformatBlock()", "reFormatBlock() called recursively");
       
   199 
       
   200     currentBlock = block;
       
   201     QTextBlock previous = block.previous();
       
   202 
       
   203     formatChanges.fill(QTextCharFormat(), block.length() - 1);
       
   204     q->highlightBlock(block.text());
       
   205     applyFormatChanges();
       
   206 
       
   207     doc->markContentsDirty(block.position(), block.length());
       
   208 
       
   209     currentBlock = QTextBlock();
       
   210 }
       
   211 
       
   212 /*!
       
   213     \class QSyntaxHighlighter
       
   214     \reentrant
       
   215 
       
   216     \brief The QSyntaxHighlighter class allows you to define syntax
       
   217     highlighting rules, and in addition you can use the class to query
       
   218     a document's current formatting or user data.
       
   219 
       
   220     \since 4.1
       
   221 
       
   222     \ingroup richtext-processing
       
   223 
       
   224     The QSyntaxHighlighter class is a base class for implementing
       
   225     QTextEdit syntax highlighters.  A syntax highligher automatically
       
   226     highlights parts of the text in a QTextEdit, or more generally in
       
   227     a QTextDocument. Syntax highlighters are often used when the user
       
   228     is entering text in a specific format (for example source code)
       
   229     and help the user to read the text and identify syntax errors.
       
   230 
       
   231     To provide your own syntax highlighting, you must subclass
       
   232     QSyntaxHighlighter and reimplement highlightBlock().
       
   233 
       
   234     When you create an instance of your QSyntaxHighlighter subclass,
       
   235     pass it the QTextEdit or QTextDocument that you want the syntax
       
   236     highlighting to be applied to. For example:
       
   237 
       
   238     \snippet doc/src/snippets/code/src_gui_text_qsyntaxhighlighter.cpp 0
       
   239 
       
   240     After this your highlightBlock() function will be called
       
   241     automatically whenever necessary. Use your highlightBlock()
       
   242     function to apply formatting (e.g. setting the font and color) to
       
   243     the text that is passed to it. QSyntaxHighlighter provides the
       
   244     setFormat() function which applies a given QTextCharFormat on
       
   245     the current text block. For example:
       
   246 
       
   247     \snippet doc/src/snippets/code/src_gui_text_qsyntaxhighlighter.cpp 1
       
   248 
       
   249     Some syntaxes can have constructs that span several text
       
   250     blocks. For example, a C++ syntax highlighter should be able to
       
   251     cope with \c{/}\c{*...*}\c{/} multiline comments. To deal with
       
   252     these cases it is necessary to know the end state of the previous
       
   253     text block (e.g. "in comment").
       
   254 
       
   255     Inside your highlightBlock() implementation you can query the end
       
   256     state of the previous text block using the previousBlockState()
       
   257     function. After parsing the block you can save the last state
       
   258     using setCurrentBlockState().
       
   259 
       
   260     The currentBlockState() and previousBlockState() functions return
       
   261     an int value. If no state is set, the returned value is -1. You
       
   262     can designate any other value to identify any given state using
       
   263     the setCurrentBlockState() function. Once the state is set the
       
   264     QTextBlock keeps that value until it is set set again or until the
       
   265     corresponding paragraph of text is deleted.
       
   266 
       
   267     For example, if you're writing a simple C++ syntax highlighter,
       
   268     you might designate 1 to signify "in comment":
       
   269 
       
   270     \snippet doc/src/snippets/code/src_gui_text_qsyntaxhighlighter.cpp 2
       
   271 
       
   272     In the example above, we first set the current block state to
       
   273     0. Then, if the previous block ended within a comment, we higlight
       
   274     from the beginning of the current block (\c {startIndex =
       
   275     0}). Otherwise, we search for the given start expression. If the
       
   276     specified end expression cannot be found in the text block, we
       
   277     change the current block state by calling setCurrentBlockState(),
       
   278     and make sure that the rest of the block is higlighted.
       
   279 
       
   280     In addition you can query the current formatting and user data
       
   281     using the format() and currentBlockUserData() functions
       
   282     respectively. You can also attach user data to the current text
       
   283     block using the setCurrentBlockUserData() function.
       
   284     QTextBlockUserData can be used to store custom settings. In the
       
   285     case of syntax highlighting, it is in particular interesting as
       
   286     cache storage for information that you may figure out while
       
   287     parsing the paragraph's text. For an example, see the
       
   288     setCurrentBlockUserData() documentation.
       
   289 
       
   290     \sa QTextEdit, {Syntax Highlighter Example}
       
   291 */
       
   292 
       
   293 /*!
       
   294     Constructs a QSyntaxHighlighter with the given \a parent.
       
   295 */
       
   296 QSyntaxHighlighter::QSyntaxHighlighter(QObject *parent)
       
   297     : QObject(*new QSyntaxHighlighterPrivate, parent)
       
   298 {
       
   299 }
       
   300 
       
   301 /*!
       
   302     Constructs a QSyntaxHighlighter and installs it on \a parent.
       
   303     The specified QTextDocument also becomes the owner of the
       
   304     QSyntaxHighlighter.
       
   305 */
       
   306 QSyntaxHighlighter::QSyntaxHighlighter(QTextDocument *parent)
       
   307     : QObject(*new QSyntaxHighlighterPrivate, parent)
       
   308 {
       
   309     setDocument(parent);
       
   310 }
       
   311 
       
   312 /*!
       
   313     Constructs a QSyntaxHighlighter and installs it on \a parent 's
       
   314     QTextDocument. The specified QTextEdit also becomes the owner of
       
   315     the QSyntaxHighlighter.
       
   316 */
       
   317 QSyntaxHighlighter::QSyntaxHighlighter(QTextEdit *parent)
       
   318     : QObject(*new QSyntaxHighlighterPrivate, parent)
       
   319 {
       
   320     setDocument(parent->document());
       
   321 }
       
   322 
       
   323 /*!
       
   324     Destructor. Uninstalls this syntax highlighter from the text document.
       
   325 */
       
   326 QSyntaxHighlighter::~QSyntaxHighlighter()
       
   327 {
       
   328     setDocument(0);
       
   329 }
       
   330 
       
   331 /*!
       
   332     Installs the syntax highlighter on the given QTextDocument \a doc.
       
   333     A QSyntaxHighlighter can only be used with one document at a time.
       
   334 */
       
   335 void QSyntaxHighlighter::setDocument(QTextDocument *doc)
       
   336 {
       
   337     Q_D(QSyntaxHighlighter);
       
   338     if (d->doc) {
       
   339         disconnect(d->doc, SIGNAL(contentsChange(int,int,int)),
       
   340                    this, SLOT(_q_reformatBlocks(int,int,int)));
       
   341 
       
   342         QTextCursor cursor(d->doc);
       
   343         cursor.beginEditBlock();
       
   344         for (QTextBlock blk = d->doc->begin(); blk.isValid(); blk = blk.next())
       
   345             blk.layout()->clearAdditionalFormats();
       
   346         cursor.endEditBlock();
       
   347     }
       
   348     d->doc = doc;
       
   349     if (d->doc) {
       
   350         connect(d->doc, SIGNAL(contentsChange(int,int,int)),
       
   351                 this, SLOT(_q_reformatBlocks(int,int,int)));
       
   352         QTimer::singleShot(0, this, SLOT(_q_delayedRehighlight()));
       
   353         d->rehighlightPending = true;
       
   354     }
       
   355 }
       
   356 
       
   357 /*!
       
   358     Returns the QTextDocument on which this syntax highlighter is
       
   359     installed.
       
   360 */
       
   361 QTextDocument *QSyntaxHighlighter::document() const
       
   362 {
       
   363     Q_D(const QSyntaxHighlighter);
       
   364     return d->doc;
       
   365 }
       
   366 
       
   367 /*!
       
   368     \since 4.2
       
   369 
       
   370     Reapplies the highlighting to the whole document.
       
   371 
       
   372     \sa rehighlightBlock()
       
   373 */
       
   374 void QSyntaxHighlighter::rehighlight()
       
   375 {
       
   376     Q_D(QSyntaxHighlighter);
       
   377     if (!d->doc)
       
   378         return;
       
   379 
       
   380     QTextCursor cursor(d->doc);
       
   381     d->rehighlight(cursor, QTextCursor::End);
       
   382 }
       
   383 
       
   384 /*!
       
   385     \since 4.6
       
   386 
       
   387     Reapplies the highlighting to the given QTextBlock \a block.
       
   388     
       
   389     \sa rehighlight()
       
   390 */
       
   391 void QSyntaxHighlighter::rehighlightBlock(const QTextBlock &block)
       
   392 {
       
   393     Q_D(QSyntaxHighlighter);
       
   394     if (!d->doc)
       
   395         return;
       
   396 
       
   397     QTextCursor cursor(block);
       
   398     d->rehighlight(cursor, QTextCursor::EndOfBlock);
       
   399 }
       
   400 
       
   401 /*!
       
   402     \fn void QSyntaxHighlighter::highlightBlock(const QString &text)
       
   403 
       
   404     Highlights the given text block. This function is called when
       
   405     necessary by the rich text engine, i.e. on text blocks which have
       
   406     changed.
       
   407 
       
   408     To provide your own syntax highlighting, you must subclass
       
   409     QSyntaxHighlighter and reimplement highlightBlock(). In your
       
   410     reimplementation you should parse the block's \a text and call
       
   411     setFormat() as often as necessary to apply any font and color
       
   412     changes that you require. For example:
       
   413 
       
   414     \snippet doc/src/snippets/code/src_gui_text_qsyntaxhighlighter.cpp 3
       
   415 
       
   416     Some syntaxes can have constructs that span several text
       
   417     blocks. For example, a C++ syntax highlighter should be able to
       
   418     cope with \c{/}\c{*...*}\c{/} multiline comments. To deal with
       
   419     these cases it is necessary to know the end state of the previous
       
   420     text block (e.g. "in comment").
       
   421 
       
   422     Inside your highlightBlock() implementation you can query the end
       
   423     state of the previous text block using the previousBlockState()
       
   424     function. After parsing the block you can save the last state
       
   425     using setCurrentBlockState().
       
   426 
       
   427     The currentBlockState() and previousBlockState() functions return
       
   428     an int value. If no state is set, the returned value is -1. You
       
   429     can designate any other value to identify any given state using
       
   430     the setCurrentBlockState() function. Once the state is set the
       
   431     QTextBlock keeps that value until it is set set again or until the
       
   432     corresponding paragraph of text gets deleted.
       
   433 
       
   434     For example, if you're writing a simple C++ syntax highlighter,
       
   435     you might designate 1 to signify "in comment". For a text block
       
   436     that ended in the middle of a comment you'd set 1 using
       
   437     setCurrentBlockState, and for other paragraphs you'd set 0.
       
   438     In your parsing code if the return value of previousBlockState()
       
   439     is 1, you would highlight the text as a C++ comment until you
       
   440     reached the closing \c{*}\c{/}.
       
   441 
       
   442     \sa previousBlockState(), setFormat(), setCurrentBlockState()
       
   443 */
       
   444 
       
   445 /*!
       
   446     This function is applied to the syntax highlighter's current text
       
   447     block (i.e. the text that is passed to the highlightBlock()
       
   448     function).
       
   449 
       
   450     The specified \a format is applied to the text from the \a start
       
   451     position for a length of \a count characters (if \a count is 0,
       
   452     nothing is done). The formatting properties set in \a format are
       
   453     merged at display time with the formatting information stored
       
   454     directly in the document, for example as previously set with
       
   455     QTextCursor's functions. Note that the document itself remains
       
   456     unmodified by the format set through this function.
       
   457 
       
   458     \sa format(), highlightBlock()
       
   459 */
       
   460 void QSyntaxHighlighter::setFormat(int start, int count, const QTextCharFormat &format)
       
   461 {
       
   462     Q_D(QSyntaxHighlighter);
       
   463 
       
   464     if (start < 0 || start >= d->formatChanges.count())
       
   465         return;
       
   466 
       
   467     const int end = qMin(start + count, d->formatChanges.count());
       
   468     for (int i = start; i < end; ++i)
       
   469         d->formatChanges[i] = format;
       
   470 }
       
   471 
       
   472 /*!
       
   473     \overload
       
   474 
       
   475     The specified \a color is applied to the current text block from
       
   476     the \a start position for a length of \a count characters.
       
   477 
       
   478     The other attributes of the current text block, e.g. the font and
       
   479     background color, are reset to default values.
       
   480 
       
   481     \sa format(), highlightBlock()
       
   482 */
       
   483 void QSyntaxHighlighter::setFormat(int start, int count, const QColor &color)
       
   484 {
       
   485     QTextCharFormat format;
       
   486     format.setForeground(color);
       
   487     setFormat(start, count, format);
       
   488 }
       
   489 
       
   490 /*!
       
   491     \overload
       
   492 
       
   493     The specified \a font is applied to the current text block from
       
   494     the \a start position for a length of \a count characters.
       
   495 
       
   496     The other attributes of the current text block, e.g. the font and
       
   497     background color, are reset to default values.
       
   498 
       
   499     \sa format(), highlightBlock()
       
   500 */
       
   501 void QSyntaxHighlighter::setFormat(int start, int count, const QFont &font)
       
   502 {
       
   503     QTextCharFormat format;
       
   504     format.setFont(font);
       
   505     setFormat(start, count, format);
       
   506 }
       
   507 
       
   508 /*!
       
   509     \fn QTextCharFormat QSyntaxHighlighter::format(int position) const
       
   510 
       
   511     Returns the format at \a position inside the syntax highlighter's
       
   512     current text block.
       
   513 */
       
   514 QTextCharFormat QSyntaxHighlighter::format(int pos) const
       
   515 {
       
   516     Q_D(const QSyntaxHighlighter);
       
   517     if (pos < 0 || pos >= d->formatChanges.count())
       
   518         return QTextCharFormat();
       
   519     return d->formatChanges.at(pos);
       
   520 }
       
   521 
       
   522 /*!
       
   523     Returns the end state of the text block previous to the
       
   524     syntax highlighter's current block. If no value was
       
   525     previously set, the returned value is -1.
       
   526 
       
   527     \sa highlightBlock(), setCurrentBlockState()
       
   528 */
       
   529 int QSyntaxHighlighter::previousBlockState() const
       
   530 {
       
   531     Q_D(const QSyntaxHighlighter);
       
   532     if (!d->currentBlock.isValid())
       
   533         return -1;
       
   534 
       
   535     const QTextBlock previous = d->currentBlock.previous();
       
   536     if (!previous.isValid())
       
   537         return -1;
       
   538 
       
   539     return previous.userState();
       
   540 }
       
   541 
       
   542 /*!
       
   543     Returns the state of the current text block. If no value is set,
       
   544     the returned value is -1.
       
   545 */
       
   546 int QSyntaxHighlighter::currentBlockState() const
       
   547 {
       
   548     Q_D(const QSyntaxHighlighter);
       
   549     if (!d->currentBlock.isValid())
       
   550         return -1;
       
   551 
       
   552     return d->currentBlock.userState();
       
   553 }
       
   554 
       
   555 /*!
       
   556     Sets the state of the current text block to \a newState.
       
   557 
       
   558     \sa highlightBlock()
       
   559 */
       
   560 void QSyntaxHighlighter::setCurrentBlockState(int newState)
       
   561 {
       
   562     Q_D(QSyntaxHighlighter);
       
   563     if (!d->currentBlock.isValid())
       
   564         return;
       
   565 
       
   566     d->currentBlock.setUserState(newState);
       
   567 }
       
   568 
       
   569 /*!
       
   570     Attaches the given \a data to the current text block.  The
       
   571     ownership is passed to the underlying text document, i.e. the
       
   572     provided QTextBlockUserData object will be deleted if the
       
   573     corresponding text block gets deleted.
       
   574 
       
   575     QTextBlockUserData can be used to store custom settings. In the
       
   576     case of syntax highlighting, it is in particular interesting as
       
   577     cache storage for information that you may figure out while
       
   578     parsing the paragraph's text.
       
   579 
       
   580     For example while parsing the text, you can keep track of
       
   581     parenthesis characters that you encounter ('{[(' and the like),
       
   582     and store their relative position and the actual QChar in a simple
       
   583     class derived from QTextBlockUserData:
       
   584 
       
   585     \snippet doc/src/snippets/code/src_gui_text_qsyntaxhighlighter.cpp 4
       
   586 
       
   587     During cursor navigation in the associated editor, you can ask the
       
   588     current QTextBlock (retrieved using the QTextCursor::block()
       
   589     function) if it has a user data object set and cast it to your \c
       
   590     BlockData object. Then you can check if the current cursor
       
   591     position matches with a previously recorded parenthesis position,
       
   592     and, depending on the type of parenthesis (opening or closing),
       
   593     find the next opening or closing parenthesis on the same level.
       
   594 
       
   595     In this way you can do a visual parenthesis matching and highlight
       
   596     from the current cursor position to the matching parenthesis. That
       
   597     makes it easier to spot a missing parenthesis in your code and to
       
   598     find where a corresponding opening/closing parenthesis is when
       
   599     editing parenthesis intensive code.
       
   600 
       
   601     \sa QTextBlock::setUserData()
       
   602 */
       
   603 void QSyntaxHighlighter::setCurrentBlockUserData(QTextBlockUserData *data)
       
   604 {
       
   605     Q_D(QSyntaxHighlighter);
       
   606     if (!d->currentBlock.isValid())
       
   607         return;
       
   608 
       
   609     d->currentBlock.setUserData(data);
       
   610 }
       
   611 
       
   612 /*!
       
   613     Returns the QTextBlockUserData object previously attached to the
       
   614     current text block.
       
   615 
       
   616     \sa QTextBlock::userData(), setCurrentBlockUserData()
       
   617 */
       
   618 QTextBlockUserData *QSyntaxHighlighter::currentBlockUserData() const
       
   619 {
       
   620     Q_D(const QSyntaxHighlighter);
       
   621     if (!d->currentBlock.isValid())
       
   622         return 0;
       
   623 
       
   624     return d->currentBlock.userData();
       
   625 }
       
   626 
       
   627 /*!
       
   628     \since 4.4
       
   629 
       
   630     Returns the current text block.
       
   631  */
       
   632 QTextBlock QSyntaxHighlighter::currentBlock() const
       
   633 {
       
   634     Q_D(const QSyntaxHighlighter);
       
   635     return d->currentBlock;
       
   636 }
       
   637 
       
   638 QT_END_NAMESPACE
       
   639 
       
   640 #include "moc_qsyntaxhighlighter.cpp"
       
   641 
       
   642 #endif // QT_NO_SYNTAXHIGHLIGHTER