• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdeedu API Reference
  • KDE Home
  • Contact Us
 

cantor/src/lib

  • sources
  • kde-4.14
  • kdeedu
  • cantor
  • src
  • lib
defaulthighlighter.cpp
Go to the documentation of this file.
1 /*
2  This program is free software; you can redistribute it and/or
3  modify it under the terms of the GNU General Public License
4  as published by the Free Software Foundation; either version 2
5  of the License, or (at your option) any later version.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin Street, Fifth Floor,
15  Boston, MA 02110-1301, USA.
16 
17  ---
18  Copyright (C) 2009 Alexander Rieder <alexanderrieder@gmail.com>
19  Copyright (C) 2006 David Saxton <david@bluehaze.org>
20 */
21 
22 #include "defaulthighlighter.h"
23 
24 #include <QtCore/QLocale>
25 #include <QTextDocument>
26 #include <QTextCursor>
27 #include <QGraphicsTextItem>
28 #include <kcolorscheme.h>
29 #include <kglobalsettings.h>
30 #include <kdebug.h>
31 #include <QStack>
32 
33 using namespace Cantor;
34 
35 struct HighlightingRule
36 {
37  QRegExp regExp;
38  QTextCharFormat format;
39 };
40 
41 bool operator==(const HighlightingRule& rule1, const HighlightingRule& rule2)
42 {
43  return rule1.regExp == rule2.regExp;
44 }
45 
46 struct PairOpener {
47  PairOpener() : position(-1), type(-1) { }
48  PairOpener(int p, int t) : position(p), type(t) { }
49 
50  int position;
51  int type;
52 };
53 
54 
55 class Cantor::DefaultHighlighterPrivate
56 {
57  public:
58  QTextCursor cursor;
59 
60  //Character formats to use for the highlighing
61  QTextCharFormat functionFormat;
62  QTextCharFormat variableFormat;
63  QTextCharFormat objectFormat;
64  QTextCharFormat keywordFormat;
65  QTextCharFormat numberFormat;
66  QTextCharFormat operatorFormat;
67  QTextCharFormat errorFormat;
68  QTextCharFormat commentFormat;
69  QTextCharFormat stringFormat;
70  QTextCharFormat matchingPairFormat;
71  QTextCharFormat mismatchingPairFormat;
72 
73  int lastBlockNumber;
74  int lastPosition;
75  // each two consecutive items build a pair
76  QList<QChar> pairs;
77 
78  QList<HighlightingRule> regExpRules;
79  QHash<QString, QTextCharFormat> wordRules;
80 };
81 
82 DefaultHighlighter::DefaultHighlighter(QObject* parent)
83  : QSyntaxHighlighter(parent),
84  d(new DefaultHighlighterPrivate)
85 {
86  d->cursor = QTextCursor();
87  d->lastBlockNumber=-1;
88  d->lastPosition=-1;
89 
90  addPair('(', ')');
91  addPair('[', ']');
92  addPair('{', '}');
93 
94  updateFormats();
95  connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), this, SLOT(updateFormats()));
96 }
97 
98 DefaultHighlighter::~DefaultHighlighter()
99 {
100  delete d;
101 }
102 
103 void DefaultHighlighter::setTextItem(QGraphicsTextItem* item)
104 {
105  d->cursor = item->textCursor();
106  setDocument(item->document());
107  // make sure every item is connected only once
108  item->disconnect(this, SLOT(positionChanged(QTextCursor)));
109  // QGraphicsTextItem has no signal cursorPositionChanged, but item really
110  // is a WorksheetTextItem
111  connect(item, SIGNAL(cursorPositionChanged(QTextCursor)),
112  this, SLOT(positionChanged(QTextCursor)));
113 
114  d->lastBlockNumber = -1;
115  d->lastPosition = -1;
116 }
117 
118 bool DefaultHighlighter::skipHighlighting(const QString& text)
119 {
120  return text.isEmpty();
121 }
122 
123 void DefaultHighlighter::highlightBlock(const QString& text)
124 {
125  //kDebug() << text;
126  const QTextCursor& cursor = d->cursor;
127  d->lastBlockNumber = cursor.blockNumber();
128 
129  if (skipHighlighting(text))
130  return;
131 
132  highlightPairs(text);
133  highlightWords(text);
134  highlightRegExps(text);
135 }
136 
137 void DefaultHighlighter::addPair(const QChar& openSymbol, const QChar& closeSymbol)
138 {
139  Q_ASSERT(!d->pairs.contains(openSymbol));
140  Q_ASSERT(!d->pairs.contains(closeSymbol));
141  d->pairs << openSymbol << closeSymbol;
142 }
143 
144 void DefaultHighlighter::highlightPairs(const QString& text)
145 {
146  //kDebug() << text;
147  const QTextCursor& cursor = d->cursor;
148  int cursorPos = -1;
149  if (cursor.blockNumber() == currentBlock().blockNumber() ) {
150  cursorPos = cursor.position() - currentBlock().position();
151  // when text changes, this will be called before the positionChanged signal
152  // gets emitted. Hence update the position so we don't highlight twice
153  d->lastPosition = cursor.position();
154  }
155 
156  QStack<PairOpener> opened;
157 
158  for (int i = 0; i < text.size(); ++i) {
159  int idx = d->pairs.indexOf(text[i]);
160  if (idx == -1)
161  continue;
162  if (idx % 2 == 0) { //opener of a pair
163  opened.push(PairOpener(i, idx));
164  } else if (opened.isEmpty()) { //closer with no previous opener
165  setFormat(i, 1, errorFormat());
166  } else if (opened.top().type == idx - 1) { //closer with matched opener
167  int openPos = opened.pop().position;
168  if (cursorPos != -1 &&
169  (openPos == cursorPos || openPos == cursorPos - 1 ||
170  i == cursorPos || i == cursorPos - 1)) {
171  setFormat(openPos, 1, matchingPairFormat());
172  setFormat(i, 1, matchingPairFormat());
173  }
174  } else { //closer with mismatching opener
175  int openPos = opened.pop().position;
176  setFormat(openPos, 1, mismatchingPairFormat());
177  setFormat(i, 1, mismatchingPairFormat());
178  }
179  }
180 
181  // handled unterminated pairs
182  while (!opened.isEmpty()) {
183  int position = opened.pop().position;
184  setFormat(position, 1, errorFormat());
185  }
186 
187 }
188 
189 void DefaultHighlighter::highlightWords(const QString& text)
190 {
191  //kDebug() << "DefaultHighlighter::highlightWords";
192 
193  const QStringList& words = text.split(QRegExp("\\b"), QString::SkipEmptyParts);
194  int count;
195  int pos = 0;
196 
197  const int n = words.size();
198  for (int i = 0; i < n; ++i)
199  {
200  count = words[i].size();
201  QString word = words[i];
202 
203  //kind of a HACK:
204  //look at previous words, if they end with allowed characters,
205  //prepend them to the current word. This allows for example
206  //to highlight words that start with a "Non-word"-character
207  //e.g. %pi in the scilab backend.
208  //kDebug() << "nonSeparatingCharacters().isNull(): " << nonSeparatingCharacters().isNull();
209  if(!nonSeparatingCharacters().isNull())
210  {
211  for(int j = i - 1; j >= 0; j--)
212  {
213  //kDebug() << "j: " << j << "w: " << words[j];
214  const QString& w = words[j];
215  const QString exp = QString("(%1)*$").arg(nonSeparatingCharacters());
216  //kDebug() << "exp: " << exp;
217  int idx = w.indexOf(QRegExp(exp));
218  const QString& s = w.mid(idx);
219  //kDebug() << "s: " << s;
220 
221  if(s.size() > 0)
222  {
223  pos -= s.size();
224  count += s.size();
225  word = s + word;
226  } else{
227  break;
228  }
229  }
230  }
231 
232  word = word.trimmed();
233 
234  //kDebug() << "highlighing: " << word;
235 
236  if (d->wordRules.contains(word))
237  {
238  setFormat(pos, count, d->wordRules[word]);
239  }
240 
241  pos += count;
242  }
243 }
244 
245 void DefaultHighlighter::highlightRegExps(const QString& text)
246 {
247  foreach (const HighlightingRule& rule, d->regExpRules)
248  {
249  int index = rule.regExp.indexIn(text);
250  while (index >= 0) {
251  int length = rule.regExp.matchedLength();
252  setFormat(index, length, rule.format);
253  index = rule.regExp.indexIn(text, index + length);
254  }
255  }
256 }
257 
258 QTextCharFormat DefaultHighlighter::functionFormat() const
259 {
260  return d->functionFormat;
261 }
262 
263 QTextCharFormat DefaultHighlighter::variableFormat() const
264 {
265  return d->variableFormat;
266 }
267 
268 QTextCharFormat DefaultHighlighter::objectFormat() const
269 {
270  return d->objectFormat;
271 }
272 
273 QTextCharFormat DefaultHighlighter::keywordFormat() const
274 {
275  return d->keywordFormat;
276 }
277 
278 QTextCharFormat DefaultHighlighter::numberFormat() const
279 {
280  return d->numberFormat;
281 }
282 
283 QTextCharFormat DefaultHighlighter::operatorFormat() const
284 {
285  return d->operatorFormat;
286 }
287 
288 QTextCharFormat DefaultHighlighter::errorFormat() const
289 {
290  return d->errorFormat;
291 }
292 
293 QTextCharFormat DefaultHighlighter::commentFormat() const
294 {
295  return d->commentFormat;
296 }
297 
298 QTextCharFormat DefaultHighlighter::stringFormat() const
299 {
300  return d->stringFormat;
301 }
302 
303 QTextCharFormat DefaultHighlighter::matchingPairFormat() const
304 {
305  return d->matchingPairFormat;
306 }
307 
308 QTextCharFormat DefaultHighlighter::mismatchingPairFormat() const
309 {
310  return d->mismatchingPairFormat;
311 }
312 
313 void DefaultHighlighter::updateFormats()
314 {
315  //initialize char-formats
316  KColorScheme scheme(QPalette::Active);
317 
318  d->functionFormat.setForeground(scheme.foreground(KColorScheme::LinkText));
319  d->functionFormat.setFontWeight(QFont::DemiBold);
320 
321  d->variableFormat.setForeground(scheme.foreground(KColorScheme::ActiveText));
322 
323  d->objectFormat.setForeground(scheme.foreground(KColorScheme::NormalText));
324  d->objectFormat.setFontWeight(QFont::Bold);
325 
326  d->keywordFormat.setForeground(scheme.foreground(KColorScheme::NeutralText));
327  d->keywordFormat.setFontWeight(QFont::Bold);
328 
329  d->numberFormat.setForeground(scheme.foreground(KColorScheme::NeutralText));
330 
331  d->operatorFormat.setForeground(scheme.foreground(KColorScheme::NormalText));
332  d->operatorFormat.setFontWeight(QFont::Bold);
333 
334  d->errorFormat.setForeground(scheme.foreground(KColorScheme::NormalText));
335  d->errorFormat.setUnderlineColor(scheme.foreground(KColorScheme::NegativeText).color());
336  d->errorFormat.setUnderlineStyle(QTextCharFormat::SpellCheckUnderline);
337 
338  d->commentFormat.setForeground(scheme.foreground(KColorScheme::InactiveText));
339 
340  d->stringFormat.setForeground(scheme.foreground(KColorScheme::PositiveText));
341 
342  d->matchingPairFormat.setForeground(scheme.foreground(KColorScheme::NeutralText));
343  d->matchingPairFormat.setBackground(scheme.background(KColorScheme::NeutralBackground));
344 
345  d->mismatchingPairFormat.setForeground(scheme.foreground(KColorScheme::NegativeText));
346  d->mismatchingPairFormat.setBackground(scheme.background(KColorScheme::NegativeBackground));
347 }
348 
349 
350 void DefaultHighlighter::positionChanged(QTextCursor cursor)
351 {
352  if (!cursor.isNull() && cursor.document() != document())
353  // A new item notified us, but we did not yet change our document.
354  // We are waiting for that to happen.
355  return;
356 
357  d->cursor = cursor;
358  if ( (cursor.isNull() || cursor.blockNumber() != d->lastBlockNumber) &&
359  d->lastBlockNumber >= 0 ) {
360  // remove highlight from last focused block
361  rehighlightBlock(document()->findBlockByNumber(d->lastBlockNumber));
362  }
363 
364  if (cursor.isNull()) {
365  d->lastBlockNumber = -1;
366  d->lastPosition = -1;
367  return;
368  }
369 
370  d->lastBlockNumber = cursor.blockNumber();
371 
372  if ( d->lastPosition == cursor.position() ) {
373  return;
374  }
375 
376  rehighlightBlock(cursor.block());
377  d->lastPosition = cursor.position();
378 }
379 
380 void DefaultHighlighter::addRule(const QString& word, const QTextCharFormat& format)
381 {
382  d->wordRules[word] = format;
383  emit rulesChanged();
384 }
385 
386 void DefaultHighlighter::addRule(const QRegExp& regexp, const QTextCharFormat& format)
387 {
388  HighlightingRule rule = { regexp, format };
389  d->regExpRules.removeAll(rule);
390  d->regExpRules.append(rule);
391 
392  emit rulesChanged();
393 }
394 
395 void DefaultHighlighter::removeRule(const QString& word)
396 {
397  d->wordRules.remove(word);
398 
399  emit rulesChanged();
400 }
401 
402 void DefaultHighlighter::removeRule(const QRegExp& regexp)
403 {
404  HighlightingRule rule = { regexp, QTextCharFormat() };
405  d->regExpRules.removeAll(rule);
406 
407  emit rulesChanged();
408 }
409 
410 QString DefaultHighlighter::nonSeparatingCharacters() const
411 {
412  return QString();
413 }
414 
415 #include "defaulthighlighter.moc"
QTextCursor::position
int position() const
QSyntaxHighlighter::currentBlock
QTextBlock currentBlock() const
Cantor::DefaultHighlighter::keywordFormat
QTextCharFormat keywordFormat() const
Definition: defaulthighlighter.cpp:273
QString::indexOf
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
QGraphicsTextItem::textCursor
textCursor
QTextCursor
QTextBlock::position
int position() const
QStack::pop
T pop()
Cantor::DefaultHighlighter::addPair
void addPair(const QChar &openSymbol, const QChar &closeSymbol)
Call this to add a pair of symbols for highlighting.
Definition: defaulthighlighter.cpp:137
Cantor::DefaultHighlighter::stringFormat
QTextCharFormat stringFormat() const
Definition: defaulthighlighter.cpp:298
QChar
QString::split
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
QStack::push
void push(const T &t)
Cantor::DefaultHighlighter::mismatchingPairFormat
QTextCharFormat mismatchingPairFormat() const
Definition: defaulthighlighter.cpp:308
Cantor::DefaultHighlighter::highlightWords
void highlightWords(const QString &text)
Highlights words added with addRule()
Definition: defaulthighlighter.cpp:189
QString::size
int size() const
Cantor::DefaultHighlighter::matchingPairFormat
QTextCharFormat matchingPairFormat() const
Definition: defaulthighlighter.cpp:303
Cantor::DefaultHighlighter::variableFormat
QTextCharFormat variableFormat() const
Definition: defaulthighlighter.cpp:263
QSyntaxHighlighter::setFormat
void setFormat(int start, int count, const QTextCharFormat &format)
Cantor::DefaultHighlighter::numberFormat
QTextCharFormat numberFormat() const
Definition: defaulthighlighter.cpp:278
QObject::disconnect
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
QSyntaxHighlighter
QList::size
int size() const
Cantor::DefaultHighlighter::operatorFormat
QTextCharFormat operatorFormat() const
Definition: defaulthighlighter.cpp:283
QRegExp
Cantor::DefaultHighlighter::nonSeparatingCharacters
virtual QString nonSeparatingCharacters() const
Returns a string that contains a regular expression that matches for characters thar are allowed insi...
Definition: defaulthighlighter.cpp:410
Cantor::DefaultHighlighter::setTextItem
void setTextItem(QGraphicsTextItem *item)
Change the item beeing highlighted.
Definition: defaulthighlighter.cpp:103
Cantor::DefaultHighlighter::commentFormat
QTextCharFormat commentFormat() const
Definition: defaulthighlighter.cpp:293
QHash< QString, QTextCharFormat >
Cantor::DefaultHighlighter::errorFormat
QTextCharFormat errorFormat() const
Definition: defaulthighlighter.cpp:288
QObject
Cantor::operator==
bool operator==(const Cantor::DefaultVariableModel::Variable &one, const Cantor::DefaultVariableModel::Variable &other)
Definition: defaultvariablemodel.cpp:194
QString::isEmpty
bool isEmpty() const
QString::trimmed
QString trimmed() const
QTextCursor::document
QTextDocument * document() const
QGraphicsTextItem
QTextCursor::isNull
bool isNull() const
Cantor::DefaultHighlighter::highlightBlock
virtual void highlightBlock(const QString &text)
This method is called by Cantor's KTextEdit and is where all the highlighting must take place...
Definition: defaulthighlighter.cpp:123
QString
Cantor::DefaultHighlighter::functionFormat
QTextCharFormat functionFormat() const
Definition: defaulthighlighter.cpp:258
QList< QChar >
QStringList
QTextCharFormat
Cantor::DefaultHighlighter::positionChanged
void positionChanged(QTextCursor)
Called when the cursor moved.
Definition: defaulthighlighter.cpp:350
QTextCursor::block
QTextBlock block() const
QGraphicsTextItem::document
QTextDocument * document() const
QSyntaxHighlighter::document
QTextDocument * document() const
Cantor::DefaultHighlighter::addRule
void addRule(const QString &word, const QTextCharFormat &format)
Highlights all instances of the word in the text with the specified format.
Definition: defaulthighlighter.cpp:380
Cantor::DefaultHighlighter::skipHighlighting
bool skipHighlighting(const QString &text)
Definition: defaulthighlighter.cpp:118
Cantor::DefaultHighlighter::highlightRegExps
void highlightRegExps(const QString &text)
Highlights all matches from regular expressions added with addRule()
Definition: defaulthighlighter.cpp:245
QSyntaxHighlighter::format
QTextCharFormat format(int position) const
Cantor::DefaultHighlighter::DefaultHighlighter
DefaultHighlighter(QObject *parent)
Definition: defaulthighlighter.cpp:82
defaulthighlighter.h
Cantor::DefaultHighlighter::~DefaultHighlighter
~DefaultHighlighter()
Definition: defaulthighlighter.cpp:98
QString::mid
QString mid(int position, int n) const
QTextCursor::blockNumber
int blockNumber() const
QVector::isEmpty
bool isEmpty() const
Cantor::DefaultHighlighter::highlightPairs
void highlightPairs(const QString &text)
Highlight pairs added with addPair()
Definition: defaulthighlighter.cpp:144
QTextBlock::blockNumber
int blockNumber() const
Cantor::DefaultHighlighter::objectFormat
QTextCharFormat objectFormat() const
Definition: defaulthighlighter.cpp:268
Cantor::DefaultHighlighter::removeRule
void removeRule(const QString &word)
Removes any rules previously added for the word word.
Definition: defaulthighlighter.cpp:395
Cantor::DefaultHighlighter::rulesChanged
void rulesChanged()
QSyntaxHighlighter::setDocument
void setDocument(QTextDocument *doc)
QSyntaxHighlighter::rehighlightBlock
void rehighlightBlock(const QTextBlock &block)
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QString::arg
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QStack
QStack::top
T & top()
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:16:33 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

cantor/src/lib

Skip menu "cantor/src/lib"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdeedu API Reference

Skip menu "kdeedu API Reference"
  • Analitza
  •     lib
  • kalgebra
  • kalzium
  •   libscience
  • kanagram
  • kig
  •   lib
  • klettres
  • marble
  • parley
  • rocs
  •   App
  •   RocsCore
  •   VisualEditor
  •   stepcore

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal