Qt 4.8
qsyntaxhighlighter.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
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 
57 
59 {
61 public:
63  : rehighlightPending(false), inReformatBlocks(false)
64  {}
65 
67 
68  void _q_reformatBlocks(int from, int charsRemoved, int charsAdded);
69  void reformatBlocks(int from, int charsRemoved, int charsAdded);
70  void reformatBlock(const QTextBlock &block);
71 
72  inline void rehighlight(QTextCursor &cursor, QTextCursor::MoveOperation operation) {
73  inReformatBlocks = true;
74  cursor.beginEditBlock();
75  int from = cursor.position();
76  cursor.movePosition(operation);
77  reformatBlocks(from, 0, cursor.position() - from);
78  cursor.endEditBlock();
79  inReformatBlocks = false;
80  }
81 
82  inline void _q_delayedRehighlight() {
83  if (!rehighlightPending)
84  return;
85  rehighlightPending = false;
86  q_func()->rehighlight();
87  }
88 
89  void applyFormatChanges();
94 };
95 
97 {
98  bool formatsChanged = false;
99 
101 
103 
104  const int preeditAreaStart = layout->preeditAreaPosition();
105  const int preeditAreaLength = layout->preeditAreaText().length();
106 
107  if (preeditAreaLength != 0) {
109  while (it != ranges.end()) {
110  if (it->start >= preeditAreaStart
111  && it->start + it->length <= preeditAreaStart + preeditAreaLength) {
112  ++it;
113  } else {
114  it = ranges.erase(it);
115  formatsChanged = true;
116  }
117  }
118  } else if (!ranges.isEmpty()) {
119  ranges.clear();
120  formatsChanged = true;
121  }
122 
123  QTextCharFormat emptyFormat;
124 
126  r.start = -1;
127 
128  int i = 0;
129  while (i < formatChanges.count()) {
130 
131  while (i < formatChanges.count() && formatChanges.at(i) == emptyFormat)
132  ++i;
133 
134  if (i >= formatChanges.count())
135  break;
136 
137  r.start = i;
138  r.format = formatChanges.at(i);
139 
140  while (i < formatChanges.count() && formatChanges.at(i) == r.format)
141  ++i;
142 
143  if (i >= formatChanges.count())
144  break;
145 
146  r.length = i - r.start;
147 
148  if (preeditAreaLength != 0) {
149  if (r.start >= preeditAreaStart)
150  r.start += preeditAreaLength;
151  else if (r.start + r.length >= preeditAreaStart)
152  r.length += preeditAreaLength;
153  }
154 
155  ranges << r;
156  formatsChanged = true;
157  r.start = -1;
158  }
159 
160  if (r.start != -1) {
161  r.length = formatChanges.count() - r.start;
162 
163  if (preeditAreaLength != 0) {
164  if (r.start >= preeditAreaStart)
165  r.start += preeditAreaLength;
166  else if (r.start + r.length >= preeditAreaStart)
167  r.length += preeditAreaLength;
168  }
169 
170  ranges << r;
171  formatsChanged = true;
172  }
173 
174  if (formatsChanged) {
175  layout->setAdditionalFormats(ranges);
177  }
178 }
179 
180 void QSyntaxHighlighterPrivate::_q_reformatBlocks(int from, int charsRemoved, int charsAdded)
181 {
182  if (!inReformatBlocks)
183  reformatBlocks(from, charsRemoved, charsAdded);
184 }
185 
186 void QSyntaxHighlighterPrivate::reformatBlocks(int from, int charsRemoved, int charsAdded)
187 {
188  rehighlightPending = false;
189 
190  QTextBlock block = doc->findBlock(from);
191  if (!block.isValid())
192  return;
193 
194  int endPosition;
195  QTextBlock lastBlock = doc->findBlock(from + charsAdded + (charsRemoved > 0 ? 1 : 0));
196  if (lastBlock.isValid())
197  endPosition = lastBlock.position() + lastBlock.length();
198  else
199  endPosition = doc->docHandle()->length();
200 
201  bool forceHighlightOfNextBlock = false;
202 
203  while (block.isValid() && (block.position() < endPosition || forceHighlightOfNextBlock)) {
204  const int stateBeforeHighlight = block.userState();
205 
206  reformatBlock(block);
207 
208  forceHighlightOfNextBlock = (block.userState() != stateBeforeHighlight);
209 
210  block = block.next();
211  }
212 
214 }
215 
217 {
219 
220  Q_ASSERT_X(!currentBlock.isValid(), "QSyntaxHighlighter::reformatBlock()", "reFormatBlock() called recursively");
221 
222  currentBlock = block;
223 
224  formatChanges.fill(QTextCharFormat(), block.length() - 1);
225  q->highlightBlock(block.text());
227 
228  currentBlock = QTextBlock();
229 }
230 
319  : QObject(*new QSyntaxHighlighterPrivate, parent)
320 {
321 }
322 
329  : QObject(*new QSyntaxHighlighterPrivate, parent)
330 {
331  setDocument(parent);
332 }
333 
340  : QObject(*new QSyntaxHighlighterPrivate, parent)
341 {
342  setDocument(parent->document());
343 }
344 
349 {
350  setDocument(0);
351 }
352 
358 {
360  if (d->doc) {
361  disconnect(d->doc, SIGNAL(contentsChange(int,int,int)),
362  this, SLOT(_q_reformatBlocks(int,int,int)));
363 
364  QTextCursor cursor(d->doc);
365  cursor.beginEditBlock();
366  for (QTextBlock blk = d->doc->begin(); blk.isValid(); blk = blk.next())
367  blk.layout()->clearAdditionalFormats();
368  cursor.endEditBlock();
369  }
370  d->doc = doc;
371  if (d->doc) {
372  connect(d->doc, SIGNAL(contentsChange(int,int,int)),
373  this, SLOT(_q_reformatBlocks(int,int,int)));
374  d->rehighlightPending = true;
375  QTimer::singleShot(0, this, SLOT(_q_delayedRehighlight()));
376  }
377 }
378 
384 {
385  Q_D(const QSyntaxHighlighter);
386  return d->doc;
387 }
388 
400 {
402  if (!d->doc)
403  return;
404 
405  QTextCursor cursor(d->doc);
406  d->rehighlight(cursor, QTextCursor::End);
407 }
408 
420 {
422  if (!d->doc || !block.isValid() || block.document() != d->doc)
423  return;
424 
425  const bool rehighlightPending = d->rehighlightPending;
426 
427  QTextCursor cursor(block);
428  d->rehighlight(cursor, QTextCursor::EndOfBlock);
429 
430  if (rehighlightPending)
431  d->rehighlightPending = rehighlightPending;
432 }
433 
493 void QSyntaxHighlighter::setFormat(int start, int count, const QTextCharFormat &format)
494 {
496  if (start < 0 || start >= d->formatChanges.count())
497  return;
498 
499  const int end = qMin(start + count, d->formatChanges.count());
500  for (int i = start; i < end; ++i)
501  d->formatChanges[i] = format;
502 }
503 
518 void QSyntaxHighlighter::setFormat(int start, int count, const QColor &color)
519 {
521  format.setForeground(color);
522  setFormat(start, count, format);
523 }
524 
539 void QSyntaxHighlighter::setFormat(int start, int count, const QFont &font)
540 {
542  format.setFont(font);
543  setFormat(start, count, format);
544 }
545 
556 {
557  Q_D(const QSyntaxHighlighter);
558  if (pos < 0 || pos >= d->formatChanges.count())
559  return QTextCharFormat();
560  return d->formatChanges.at(pos);
561 }
562 
571 {
572  Q_D(const QSyntaxHighlighter);
573  if (!d->currentBlock.isValid())
574  return -1;
575 
576  const QTextBlock previous = d->currentBlock.previous();
577  if (!previous.isValid())
578  return -1;
579 
580  return previous.userState();
581 }
582 
588 {
589  Q_D(const QSyntaxHighlighter);
590  if (!d->currentBlock.isValid())
591  return -1;
592 
593  return d->currentBlock.userState();
594 }
595 
602 {
604  if (!d->currentBlock.isValid())
605  return;
606 
607  d->currentBlock.setUserState(newState);
608 }
609 
645 {
647  if (!d->currentBlock.isValid())
648  return;
649 
650  d->currentBlock.setUserData(data);
651 }
652 
660 {
661  Q_D(const QSyntaxHighlighter);
662  if (!d->currentBlock.isValid())
663  return 0;
664 
665  return d->currentBlock.userData();
666 }
667 
677 {
678  Q_D(const QSyntaxHighlighter);
679  return d->currentBlock;
680 }
681 
683 
684 #include "moc_qsyntaxhighlighter.cpp"
685 
686 #endif // QT_NO_SYNTAXHIGHLIGHTER
void rehighlight()
Reapplies the highlighting to the whole document.
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition: qcolor.h:67
double d
Definition: qnumeric_p.h:62
void setAdditionalFormats(const QList< FormatRange > &overrides)
Sets the additional formats supported by the text layout to formatList.
virtual ~QSyntaxHighlighter()
Destructor.
The QTextLayout::FormatRange structure is used to apply extra formatting information for a specified ...
Definition: qtextlayout.h:128
void endEditBlock()
Indicates the end of a block of editing operations on the document that should appear as a single ope...
QString text() const
Returns the block&#39;s contents as plain text.
The QTextCharFormat class provides formatting information for characters in a QTextDocument.
Definition: qtextformat.h:372
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
Definition: qglobal.h:1215
QSyntaxHighlighter(QObject *parent)
Constructs a QSyntaxHighlighter with the given parent.
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
QVector< T > & fill(const T &t, int size=-1)
Assigns value to all items in the vector.
Definition: qvector.h:665
#define it(className, varName)
QTextDocument * document() const
Returns the QTextDocument on which this syntax highlighter is installed.
int count(const T &t) const
Returns the number of occurrences of value in the vector.
Definition: qvector.h:742
int length() const
Returns the number of characters in this string.
Definition: qstring.h:696
#define SLOT(a)
Definition: qobjectdefs.h:226
iterator begin()
Returns an STL-style iterator pointing to the first item in the list.
Definition: qlist.h:267
void setFont(const QFont &font)
Sets the text format&#39;s font.
void setFormat(int start, int count, const QTextCharFormat &format)
This function is applied to the syntax highlighter&#39;s current text block (i.e.
int start
Specifies the beginning of the format range within the text layout&#39;s text.
Definition: qtextlayout.h:129
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
#define Q_D(Class)
Definition: qglobal.h:2482
void markContentsDirty(int from, int length)
Marks the contents specified by the given position and length as "dirty", informing the document that...
int previousBlockState() const
Returns the end state of the text block previous to the syntax highlighter&#39;s current block...
bool isEmpty() const
Returns true if the list contains no items; otherwise returns false.
Definition: qlist.h:152
QTextBlock next() const
Returns the text block in the document after this block, or an empty text block if this is the last o...
#define Q_Q(Class)
Definition: qglobal.h:2483
int position() const
Returns the index of the block&#39;s first character within the document.
#define SIGNAL(a)
Definition: qobjectdefs.h:227
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
void clear()
Removes all the elements from the vector and releases the memory used by the vector.
Definition: qvector.h:347
static bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
Creates a connection of the given type from the signal in the sender object to the method in the rece...
Definition: qobject.cpp:2580
QTextDocumentPrivate * docHandle() const
So that not all classes have to be friends of each other.
The QTextCursor class offers an API to access and modify QTextDocuments.
Definition: qtextcursor.h:70
iterator end()
Returns an STL-style iterator pointing to the imaginary item after the last item in the list...
Definition: qlist.h:270
const char * layout
The QTextBlock class provides a container for text fragments in a QTextDocument.
Definition: qtextobject.h:199
static const char * data(const QByteArray &arr)
void setCurrentBlockUserData(QTextBlockUserData *data)
Attaches the given data to the current text block.
void clear()
Removes all items from the list.
Definition: qlist.h:764
int position() const
Returns the absolute position of the cursor within the document.
int length() const
Returns the length of the block in characters.
int currentBlockState() const
Returns the state of the current text block.
QTextBlock currentBlock() const
Returns the current text block.
QPointer< QTextDocument > doc
void rehighlightBlock(const QTextBlock &block)
Reapplies the highlighting to the given QTextBlock block.
int preeditAreaPosition() const
Returns the position of the area in the text layout that will be processed before editing occurs...
const T & at(int i) const
Returns the item at index position i in the vector.
Definition: qvector.h:350
void _q_reformatBlocks(int from, int charsRemoved, int charsAdded)
The QTextBlockUserData class is used to associate custom data with blocks of text.
Definition: qtextobject.h:194
void setCurrentBlockState(int newState)
Sets the state of the current text block to newState.
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
Disconnects signal in object sender from method in object receiver.
Definition: qobject.cpp:2895
int userState() const
Returns the integer value previously set with setUserState() or -1.
void reformatBlock(const QTextBlock &block)
QString preeditAreaText() const
Returns the text that is inserted in the layout before editing occurs.
#define Q_ASSERT_X(cond, where, what)
Definition: qglobal.h:1837
iterator erase(iterator pos)
Removes the item associated with the iterator pos from the list, and returns an iterator to the next ...
Definition: qlist.h:464
The QTextLayout class is used to lay out and render text.
Definition: qtextlayout.h:105
void beginEditBlock()
Indicates the start of a block of editing operations on the document that should appear as a single o...
#define Q_DECLARE_PUBLIC(Class)
Definition: qglobal.h:2477
void rehighlight(QTextCursor &cursor, QTextCursor::MoveOperation operation)
The QFont class specifies a font used for drawing text.
Definition: qfont.h:64
QTextBlock findBlock(int pos) const
Returns the text block that contains the {pos}-th character.
The QSyntaxHighlighter class allows you to define syntax highlighting rules, and in addition you can ...
void reformatBlocks(int from, int charsRemoved, int charsAdded)
QList< FormatRange > additionalFormats() const
Returns the list of additional formats supported by the text layout.
QObject * parent() const
Returns a pointer to the parent object.
Definition: qobject.h:273
QTextDocument * document() const
Returns a pointer to the underlying document.
Definition: qtextedit.cpp:804
int length() const
This function is identical to count().
Definition: qlist.h:281
bool singleShot
This static function calls a slot after a given time interval.
Definition: qtimer.h:59
bool movePosition(MoveOperation op, MoveMode=MoveAnchor, int n=1)
Moves the cursor by performing the given operation n times, using the specified mode, and returns true if all operations were completed successfully; otherwise returns false.
QObject * parent
Definition: qobject.h:92
The QTextDocument class holds formatted text that can be viewed and edited using a QTextEdit...
bool isValid() const
Returns true if this text block is valid; otherwise returns false.
Definition: qtextobject.h:208
int length
Specifies the numer of characters the format range spans.
Definition: qtextlayout.h:130
QTextCharFormat format
Specifies the format to apply.
Definition: qtextlayout.h:131
void setForeground(const QBrush &brush)
Sets the foreground brush to the specified brush.
Definition: qtextformat.h:350
QTextCharFormat format(int pos) const
Returns the format at position inside the syntax highlighter&#39;s current text block.
void setDocument(QTextDocument *doc)
Installs the syntax highlighter on the given QTextDocument doc.
static const KeyPair *const end
QTextBlockUserData * currentBlockUserData() const
Returns the QTextBlockUserData object previously attached to the current text block.
QVector< QTextCharFormat > formatChanges
const QTextDocument * document() const
Returns the text document this text block belongs to, or 0 if the text block does not belong to any d...
The QTextEdit class provides a widget that is used to edit and display both plain and rich text...
Definition: qtextedit.h:70
QTextLayout * layout() const
Returns the QTextLayout that is used to lay out and display the block&#39;s contents. ...