[KLF Backend][KLF Tools][KLF Home]
KLatexFormula Project
klflatexedit.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * file klflatexedit.cpp
3 * This file is part of the KLatexFormula Project.
4 * Copyright (C) 2011 by Philippe Faist
5 * philippe.faist at bluewin.ch
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the *
19 * Free Software Foundation, Inc., *
20 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21 ***************************************************************************/
22/* $Id$ */
23
24#include <QObject>
25#include <QWidget>
26#include <QStack>
27#include <QTextEdit>
28#include <QTextDocumentFragment>
29#include <QTextCursor>
30#include <QAction>
31#include <QMenu>
32
33#include <klfguiutil.h>
34
35
36#include "klflatexedit.h"
37#include "klflatexedit_p.h"
38
39
40
41// --------------------------
42
43struct KLFLatexParenSpecsPrivate
44{
45 typedef KLFLatexParenSpecs::ParenSpec ParenSpec;
46 typedef KLFLatexParenSpecs::ParenModifierSpec ParenModifierSpec;
47
49 {
50 }
51
52 QList<ParenSpec> parens;
54
55 QStringList openParenListCache;
56 QStringList closeParenListCache;
57 QStringList openParenModifiersCache;
58 QStringList closeParenModifiersCache;
59
60 void load(const QList<ParenSpec>& pl, const QList<ParenModifierSpec>& ml)
61 {
62 openParenListCache.clear();
63 closeParenListCache.clear();
64 openParenModifiersCache.clear();
65 closeParenModifiersCache.clear();
66
67 parens = pl;
68 modifiers = ml;
69 foreach (ParenSpec p, pl) {
70 openParenListCache << p.open;
71 closeParenListCache << p.close;
72 }
73 foreach (ParenModifierSpec m, ml) {
74 openParenModifiersCache << m.openmod;
75 closeParenModifiersCache << m.closemod;
76 }
77 }
78};
79
84 << KLFLatexParenSpecs::ParenSpec("\\{", "\\}")
90 ;
91
93 << KLFLatexParenSpecs::ParenModifierSpec("\\left", "\\right")
94 << KLFLatexParenSpecs::ParenModifierSpec("\\bigl", "\\bigr")
95 << KLFLatexParenSpecs::ParenModifierSpec("\\Bigl", "\\Bigr")
96 ;
97
98// loads the default paren & paren modifier specs
100{
102 d->load(default_parens, default_mods);
103}
104// loads the given paren & paren modifier spec list
106{
108 d->load(parens, modifiers);
109}
110
112{
114 d->load(other.d->parens, other.d->modifiers);
115}
120
121
130
132{
133 return d->openParenListCache;
134}
136{
137 return d->closeParenListCache;
138}
140{
141 return d->openParenModifiersCache;
142}
144{
145 return d->closeParenModifiersCache;
146}
147
148int KLFLatexParenSpecs::identifyParen(const QString& parenstr, uint identflags)
149{
150 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
151 klfDbg("parenstr="<<parenstr<<", ifl="<<identflags) ;
152 int k;
153 for (k = 0; k < d->parens.size(); ++k) {
154 ParenSpec p = d->parens[k];
155 if ((identflags & IdentifyFlagOpen) && p.open == parenstr)
156 return k;
157 if ((identflags & IdentifyFlagClose) && p.close == parenstr)
158 return k;
159 }
160 klfWarning("Can't find paren "<<parenstr<<" (fl="<<identflags<<") in our specs!") ;
161 return -1;
162}
163
164int KLFLatexParenSpecs::identifyModifier(const QString& modstr, uint identflags)
165{
166 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
167 klfDbg("modstr="<<modstr<<", ifl="<<identflags) ;
168 int k;
169 for (k = 0; k < d->modifiers.size(); ++k) {
170 ParenModifierSpec p = d->modifiers[k];
171 if ((identflags & IdentifyFlagOpen) && p.openmod == modstr)
172 return k;
173 if ((identflags & IdentifyFlagClose) && p.closemod == modstr)
174 return k;
175 }
176 klfWarning("Can't find paren modifier "<<modstr<<" (fl="<<identflags<<") in our specs!") ;
177 return -1;
178}
179
180
181// --------------------------
182
183// static
184// this will load the default set of paren specs
186
188{
190 "parenSpecIndex is not valid! Using heuristic for parenIsLatexBrace().",
191 return parenstr=="{" || parenstr=="}"; ) ;
192
194}
195
196
197// --------------------------
198
200 : QTextEdit(parent)
201{
203
204 d->mSyntaxHighlighter = new KLFLatexSyntaxHighlighter(this, this);
205
206 connect(this, SIGNAL(cursorPositionChanged()),
207 d->mSyntaxHighlighter, SLOT(refreshAll()));
208
209 setContextMenuPolicy(Qt::DefaultContextMenu);
210
211 setProperty("klfDontChange_font", QVariant(true));
212
213 setProperty("paletteDefault", QVariant::fromValue<QPalette>(palette()));
214 QPalette pal = palette();
215 pal.setColor(QPalette::Base, QColor(255, 255, 255, 150)); // quite transparent, but lighter
216 setProperty("paletteMacBrushedMetalLook", QVariant::fromValue<QPalette>(pal));
217
218 setWordWrapMode(QTextOption::WrapAnywhere);
219}
220
225
227{
228 return toPlainText();
229}
231{
232 return d->pHeightHintLines;
233}
235{
236 d->mDropHandler = handler;
237}
239{
240 return d->mSyntaxHighlighter;
241}
242
244{
245 setLatex("");
246 setFocus();
247 d->mSyntaxHighlighter->resetEditing();
248}
249
251{
252 // don't call setPlainText(); we want to preserve undo history
253 QTextCursor cur = textCursor();
254 cur.beginEditBlock();
255 cur.select(QTextCursor::Document);
256 cur.removeSelectedText();
257 cur.insertText(latex);
258 cur.endEditBlock();
259}
260
262{
263 return wordWrapMode() != QTextOption::NoWrap;
264}
266{
267 setWordWrapMode(wrap ? QTextOption::WrapAnywhere : QTextOption::NoWrap);
268}
269
270
272{
273 QSize superSizeHint = QTextEdit::sizeHint();
274 if (d->pHeightHintLines >= 0) {
275 return QSize(superSizeHint.width(), 4 + QFontMetrics(font()).height()*d->pHeightHintLines);
276 }
277 return superSizeHint;
278}
279
281{
282 d->pHeightHintLines = lines;
283 updateGeometry();
284}
285
286
288{
289 QPoint pos = event->pos();
290 int k;
291
292 if ( ! textCursor().hasSelection() ) {
293 // move cursor at that point, but not if we have a selection
294 setTextCursor(cursorForPosition(pos));
295 }
296
297 QMenu * menu = createStandardContextMenu(mapToGlobal(pos));
298
299 QList<QAction*> actionList;
300 emit insertContextMenuActions(pos, &actionList);
301
302 if (actionList.size()) {
303 menu->addSeparator();
304 for (k = 0; k < actionList.size(); ++k) {
305 menu->addAction(actionList[k]);
306 }
307 }
308
309 menu->popup(mapToGlobal(pos));
310 event->accept();
311}
312
313
315{
316 klfDbg("formats: "<<data->formats());
317 if (d->mDropHandler != NULL)
318 if (d->mDropHandler->canOpenDropData(data))
319 return true; // data can be opened by main window
320
321 // or check if we can insert the data ourselves
322 return QTextEdit::canInsertFromMimeData(data);
323}
324
326{
327 klfDbg("formats: "<<data->formats());
328 if (d->mDropHandler != NULL) {
329 int res = d->mDropHandler->openDropData(data);
331 return; // data was opened by main window
333 // NO: eg. for plain text, try again with QTextEdit's paste
334 // // failed to open data, don't insist.
335 // return;
336 }
337 }
338
339 klfDbg("mDropHandler="<<d->mDropHandler<<" did not handle the paste, doing it ourselves.") ;
340
341 // insert the data ourselves
342 QTextEdit::insertFromMimeData(data);
343}
344
345void KLFLatexEdit::insertDelimiter(const QString& delim, int charsBack)
346{
347 QTextCursor c1 = textCursor();
348 c1.beginEditBlock();
349 QString selected = c1.selection().toPlainText();
350 QString toinsert = delim;
351 if (selected.length())
352 toinsert.insert(toinsert.length()-charsBack, selected);
354 c1.insertText(toinsert);
355 c1.endEditBlock();
356
357 if (selected.isEmpty())
358 c1.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor, charsBack);
359
360 setTextCursor(c1);
361
362 setFocus();
363}
364
366{
367 QTextEdit::setPalette(pal);
368}
369
370void KLFLatexEditPrivate::slotInsertFromActionSender()
371{
372 QObject *obj = sender();
373 if (obj == NULL || !obj->inherits("QAction")) {
374 qWarning()<<KLF_FUNC_NAME<<": sender object is not a QAction: "<<obj;
375 return;
376 }
377 QVariant v = qobject_cast<QAction*>(obj)->data();
378 QVariantMap vdata = v.toMap();
379 K->insertDelimiter(vdata["delim"].toString(), vdata["charsBack"].toInt());
380}
381
382
383// ------------------------------------
384
385
387 : QSyntaxHighlighter(parent) , _textedit(textedit)
388{
389 setDocument(textedit->document());
390
391 // some reasonable defaults for our config...
392 pConf.enabled = true;
393 pConf.highlightParensOnly = false;
394 pConf.highlightLonelyParens = true;
395
396 pConf.fmtKeyword.setForeground(QColor(0, 0, 128));
397 pConf.fmtComment.setForeground(QColor(180, 0, 0));
398 pConf.fmtComment.setFontItalic(true);
399 pConf.fmtParenMatch.setBackground(QColor(180, 238, 180));
400 pConf.fmtParenMismatch.setBackground(QColor(255, 20, 147));
401 pConf.fmtLonelyParen.setForeground(QColor(255, 0, 255));
402 pConf.fmtLonelyParen.setFontWeight(QFont::Bold);
403
404 _caretpos = 0;
405}
406
410
411
413{
414 pConf.enabled = on;
415}
416
418{
419 pConf.highlightParensOnly = on;
420}
422{
423 pConf.highlightLonelyParens = on;
424}
426{
427 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
428 KLF_ASSERT_CONDITION(f.isCharFormat(), "Format "<<f<<" is not a QTextCharFormat.", return ; ) ;
429 pConf.fmtKeyword = f.toCharFormat();
430}
432{
433 KLF_ASSERT_CONDITION(f.isCharFormat(), "Format "<<f<<" is not a QTextCharFormat.", return ; ) ;
434 pConf.fmtComment = f.toCharFormat();
435}
437{
438 KLF_ASSERT_CONDITION(f.isCharFormat(), "Format "<<f<<" is not a QTextCharFormat.", return ; ) ;
439 pConf.fmtParenMatch = f.toCharFormat();
440}
442{
443 KLF_ASSERT_CONDITION(f.isCharFormat(), "Format "<<f<<" is not a QTextCharFormat.", return ; ) ;
444 pConf.fmtParenMismatch = f.toCharFormat();
445}
447{
448 KLF_ASSERT_CONDITION(f.isCharFormat(), "Format "<<f<<" is not a QTextCharFormat.", return ; ) ;
449 pConf.fmtLonelyParen = f.toCharFormat();
450}
451
452
454/* */ KLFLatexSyntaxHighlighter::parsedBlocksForPos(int pos, unsigned int filter_mask) const
455{
456 klfDbg("pos="<<pos<<", filter_mask="<<klfFmtCC("%06x", filter_mask)<<"; total # of blocks="
457 <<pParsedBlocks.size()) ;
458 int k;
459 QList<ParsedBlock> blocks;
460 for (k = 0; k < pParsedBlocks.size(); ++k) {
461 klfDbg("testing block #"<<k<<": "<<pParsedBlocks[k]<<"; block/pos+block/len="
462 <<pParsedBlocks[k].pos+pParsedBlocks[k].len<<" compared to pos="<<pos) ;
463 if (pParsedBlocks[k].pos <= pos && pos <= pParsedBlocks[k].pos+pParsedBlocks[k].len) {
464 if (filter_mask & (1 << pParsedBlocks[k].type)) {
465 blocks << pParsedBlocks[k];
466 klfDbg("... added #"<<k) ;
467 }
468 }
469 }
470 return blocks; // return only the relevant blocks that intersect with position 'pos'
471}
472
473
474
476{
477 _caretpos = position;
478}
479
484
485void KLFLatexSyntaxHighlighter::parseEverything()
486{
487 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
488
489 QString text;
490 int i = 0;
491 int blockpos;
492 QList<uint> blocklens; // the length of each block
493 QStack<ParenItem> parens; // the parens that we'll meet
494 QList<LonelyParenItem> lonelyparens; // extra lonely parens that we can't close within the text
495
496 QTextBlock block = document()->firstBlock();
497
500 QString sopenrx =
501 "^(?:("+QStringList(klfListMap(ParsedBlock::parenSpecs.openParenModifiers(), &QRegExp::escape)).join("|")+")\\s*)?"
502 "(" + QStringList(klfListMap(ParsedBlock::parenSpecs.openParenList(), &QRegExp::escape)).join("|")+")";
503 QString scloserx =
504 "^(?:("+QStringList(klfListMap(ParsedBlock::parenSpecs.closeParenModifiers(), &QRegExp::escape)).join("|")+")\\s*)?"
505 "(" + QStringList(klfListMap(ParsedBlock::parenSpecs.closeParenList(), &QRegExp::escape)).join("|")+")";
506 klfDbg("open-paren-rx string: "<<sopenrx<<"; close-paren-rx string: "<<scloserx);
507 QRegExp rx_open(sopenrx);
508 QRegExp rx_close(scloserx);
509
510 // needed to avoid double-parsing of eg. "\\left(" when parsing "\\left(" and then "("
511 int lastparenparsingendpos = 0;
512
513 _rulestoapply.clear();
514 pParsedBlocks.clear();
515 int k;
516 while (block.isValid()) {
517 text = block.text();
518 i = 0;
519 blockpos = block.position();
520 blocklens.append(block.length());
521
522 while (text.length() < block.length()) {
523 text += "\n";
524 }
525
526 i = 0;
527 while ( i < text.length() ) {
528 if (text[i] == '%') {
529 k = 0;
530 while (i+k < text.length() && text[i+k] != '\n')
531 ++k;
532 _rulestoapply.append(FormatRule(blockpos+i, k, FComment));
533 pParsedBlocks.append(ParsedBlock(ParsedBlock::Comment, blockpos+i, k));
534 i += k + 1;
535 continue;
536 }
537 if ( blockpos+i >= lastparenparsingendpos && rx_open.indexIn(text.mid(i)) != -1) {
538 ParenItem p;
539 p.isopening = true;
540 p.parenstr = rx_open.cap(2);
541 p.modifier = rx_open.cap(1);
542 p.beginpos = blockpos+i;
543 p.endpos = blockpos+i+rx_open.matchedLength();
544 p.pos = blockpos+i+p.modifier.length();
545 p.highlight = (_caretpos == p.caretHoverPos());
546 parens.push(p);
547 lastparenparsingendpos = p.endpos;
548 }
549 else if ( blockpos+i >= lastparenparsingendpos && rx_close.indexIn(text.mid(i)) != -1) {
550 ParenItem cp;
551 cp.isopening = false;
552 cp.parenstr = rx_close.cap(2);
553 cp.modifier = rx_close.cap(1);
554 cp.beginpos = blockpos+i;
555 cp.pos = blockpos+i+cp.modifier.length();
556 cp.endpos = blockpos+i+rx_close.matchedLength();
557 cp.highlight = (_caretpos == cp.caretHoverPos());
558 lastparenparsingendpos = cp.endpos;
559
560 ParenItem p;
561 if (!parens.empty()) {
562 // first try to match the same paren type, perhaps leaving a lonely unmatched paren between,
563 // eg. in "sin[\theta(1+t]", match both square brackets leaving the paren lonely.
564 // Do this on a copy of the stack, in case we don't find a matching paren
565 QStack<ParenItem> ptrymatch = parens;
566 QList<LonelyParenItem> extralonelyparens;
567 while (ptrymatch.size() && !cp.matches(ptrymatch.top())) {
568 extralonelyparens << LonelyParenItem(ptrymatch.top(), cp.beginpos);
569 ptrymatch.pop();
570 }
571 if (ptrymatch.size()) { // found match
572 parens = ptrymatch;
573 lonelyparens << extralonelyparens;
574 p = parens.top();
575 parens.pop();
576 } else {
577 // No match found, report a lonely paren.
578 int topparenstackpos = 0;
579 if (parens.size()) {
580 topparenstackpos = parens.top().endpos;
581 }
582 lonelyparens << LonelyParenItem(cp, topparenstackpos);
583 continue; // mismatch will be reported when processing lonely parens
584 }
585 } else {
586 lonelyparens << LonelyParenItem(cp, 0);
587 continue; // mismatch will be reported when processing lonely parens
588 }
589 Format col;
590 if (cp.matches(p))
591 col = FParenMatch;
592 else
593 col = FParenMismatch;
594
595 // does this rule span multiple paragraphs, and do we need to show it (eg. cursor right after paren)
596 if (p.highlight || cp.highlight) {
597 if (pConf.highlightParensOnly) {
598 _rulestoapply.append(FormatRule(p.pos, p.poslength(), col, true));
599 _rulestoapply.append(FormatRule(cp.pos, cp.poslength(), col, true));
600 } else {
601 _rulestoapply.append(FormatRule(p.pos, cp.endpos - p.pos, col, true));
602 }
603 }
604 ParsedBlock pblk1(ParsedBlock::Paren, p.beginpos, p.beginposlength());
605 ParsedBlock pblk2(ParsedBlock::Paren, cp.beginpos, cp.beginposlength());
606 pblk1.parenmatch = ((col == FParenMatch) ? ParsedBlock::Matched : ParsedBlock::Mismatched);
607 pblk1.parenisopening = true;
608 pblk1.parenSpecIndex =
610 pblk1.parenstr = p.parenstr;
611 pblk1.parenmodifier = p.modifier;
612 pblk1.parenotherpos = cp.beginpos;
613 pblk2.parenmatch = pblk1.parenmatch;
614 pblk2.parenisopening = false;
615 pblk2.parenSpecIndex =
617 pblk2.parenstr = cp.parenstr;
618 pblk2.parenmodifier = cp.modifier;
619 pblk2.parenotherpos = p.beginpos;
620 pParsedBlocks.append(pblk1);
621 pParsedBlocks.append(pblk2);
622 }
623
624 if (text[i] == '\\') { // a keyword ("\symbol")
625 ++i;
626 k = 0;
627 if (i >= text.length())
628 continue;
629 while (i+k < text.length() && ( (text[i+k] >= 'a' && text[i+k] <= 'z') ||
630 (text[i+k] >= 'A' && text[i+k] <= 'Z') ))
631 ++k;
632 if (k == 0 && i+1 < text.length())
633 k = 1;
634
635 QString symbol = text.mid(i-1,k+1); // from i-1, length k+1
636
637 _rulestoapply.append(FormatRule(blockpos+i-1, k+1, FKeyWord));
638 ParsedBlock pblk(ParsedBlock::Keyword, blockpos+i-1, k+1);
639 pblk.keyword = symbol;
640 pParsedBlocks.append(pblk);
641
642 if (symbol.size() > 1) { // no empty backslash
643 klfDbg("symbol="<<symbol<<" i="<<i<<" k="<<k<<" caretpos="<<_caretpos<<" blockpos="<<blockpos);
644 if ( (_caretpos < blockpos+i ||_caretpos >= blockpos+i+k+1) &&
645 !pTypedSymbols.contains(symbol)) { // not typing symbol
646 klfDbg("newSymbolTyped() about to be emitted for : "<<symbol);
647 emit newSymbolTyped(symbol);
648 pTypedSymbols.append(symbol);
649 }
650 }
651 i += k;
652 continue;
653 }
654
655 if (!text[i].isPrint() && text[i] != '\n' && text[i] != '\t' && text[i] != '\r') {
657 _rulestoapply.append(FormatRule(blockpos+i-1, blockpos+i+1, FParenMismatch));
658 }
659
660 ++i;
661 }
662
663 block = block.next();
664 }
665
666 QTextBlock lastblock = document()->lastBlock();
667
668 int globendpos = lastblock.position()+lastblock.length();
669
670 klfDbg("maybe have some parens left, that are to be shown as lonely? "<<!parens.empty()) ;
671
672 // collect lonely parens list: all unclosed parens should be added to the list of collected
673 // unclosed parens.
674 while (!parens.empty()) {
675 lonelyparens << LonelyParenItem(parens.top(), globendpos);
676 parens.pop();
677 }
678
679 klfDbg("about to treat "<<lonelyparens.size()<<" lonely parens...") ;
680
681 for (k = 0; k < lonelyparens.size(); ++k) {
682 // for each unclosed paren
683 LonelyParenItem p = lonelyparens[k];
684
685 ParsedBlock pblk(ParsedBlock::Paren, p.beginpos, p.beginposlength());
686 pblk.parenmatch = ParsedBlock::Lonely;
687 pblk.parenisopening = p.isopening;
689 pblk.parenSpecIndex =
690 ParsedBlock::parenSpecs.identifyParen(p.parenstr, iff);
691 pblk.parenstr = p.parenstr;
692 pblk.parenmodifier = p.modifier;
693 pblk.parenotherpos = -1;
694
695 pParsedBlocks.append(pblk);
696
697 // if the paren was marked with flag that it can be alone, do not report error
698 if (pblk.parenSpecIndex >= 0 &&
699 (ParsedBlock::parenSpecs.parenSpecList()[pblk.parenSpecIndex].flags &
701 continue;
702 }
703
704 // otherwise, report the lonely paren
705
706 int chp = p.caretHoverPos();
707 if (chp == _caretpos) {
708 if (pConf.highlightParensOnly) {
709 _rulestoapply.append(FormatRule(p.pos, p.poslength(), FParenMismatch, true));
710 } else {
711 // FormatRule will accept a negative length
712 _rulestoapply.append(FormatRule(chp, p.unmatchedpos-chp,
713 FParenMismatch, true));
714 }
715 }
716 // highlight the lonely paren
717 if (pConf.highlightLonelyParens)
718 _rulestoapply.append(FormatRule(p.pos, p.poslength(), FLonelyParen));
719 }
720
721}
722
723QTextCharFormat KLFLatexSyntaxHighlighter::charfmtForFormat(Format f)
724{
725 QTextCharFormat fmt;
726 switch (f) {
727 case FNormal:
728 fmt = QTextCharFormat();
729 break;
730 case FKeyWord:
731 fmt = pConf.fmtKeyword;
732 break;
733 case FComment:
734 fmt = pConf.fmtComment;
735 break;
736 case FParenMatch:
737 fmt = pConf.fmtParenMatch;
738 break;
739 case FParenMismatch:
740 fmt = pConf.fmtParenMismatch;
741 break;
742 case FLonelyParen:
743 fmt = pConf.fmtLonelyParen;
744 break;
745 default:
746 fmt = QTextCharFormat();
747 break;
748 };
749 return fmt;
750}
751
752
754{
755 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
756
757 klfDbg("text is "<<text);
758
759 if ( ! pConf.enabled )
760 return; // forget everything about synt highlight if we don't want it.
761
762 QTextBlock block = currentBlock();
763
764 // printf("\t -- block/position=%d\n", block.position());
765
766 if (block.position() == 0) {
767 setCaretPos(_textedit->textCursor().position());
768 parseEverything();
769 }
770
771 QList<FormatRule> blockfmtrules;
772
773 blockfmtrules.append(FormatRule(0, text.length(), FNormal));
774
775 int k, j;
776 for (k = 0; k < _rulestoapply.size(); ++k) {
777 int start = _rulestoapply[k].pos - block.position();
778 int len = _rulestoapply[k].len;
779
780 if (start < 0) { // the rule starts before current paragraph
781 len += start; // "+" because start is negative
782 start = 0;
783 }
784 if (start > text.length())
785 continue;
786 if (len > text.length() - start)
787 len = text.length() - start;
788
789 if (len <= 0)
790 continue; // empty rule...
791
792 // apply rule
793 klfDbg("Applying rule start="<<start<<", len="<<len<<", ...") ;
794 blockfmtrules.append(FormatRule(start, len, _rulestoapply[k].format, _rulestoapply[k].onlyIfFocus));
795 }
796
797 bool hasfocus = _textedit->hasFocus();
798
799 klfDbg("About to merge text formats... text.length()="<<text.length()) ;
800 QVector<QTextCharFormat> charformats;
801 charformats.resize(text.length());
802 for (k = 0; k < blockfmtrules.size(); ++k) {
803 klfDbg("got block-fmt-rule #"<<k<<"; start="<<blockfmtrules[k].pos<<", len="<<blockfmtrules[k].len
804 <<", end="<<blockfmtrules[k].end()) ;
805 for (j = blockfmtrules[k].pos; j < blockfmtrules[k].end(); ++j) {
806 if ( ! blockfmtrules[k].onlyIfFocus || hasfocus )
807 charformats[j].merge(charfmtForFormat(blockfmtrules[k].format));
808 }
809 }
810 klfDbg("About to apply char formats...") ;
811 for (j = 0; j < charformats.size(); ++j) {
812 setFormat(j, 1, charformats[j]);
813 }
814
815 return;
816}
817
818
820{
821 pTypedSymbols = QStringList();
822}
823
824
825
826
828{
829 QString stype;
830 switch (p.type) {
831 case KLFLatexSyntaxHighlighter::ParsedBlock::Normal: stype = "-"; break;
832 case KLFLatexSyntaxHighlighter::ParsedBlock::Keyword: stype = "Keyword"; break;
833 case KLFLatexSyntaxHighlighter::ParsedBlock::Comment: stype = "Comment"; break;
834 case KLFLatexSyntaxHighlighter::ParsedBlock::Paren: stype = "Paren"; break;
835 default: stype = "<error>"; break;
836 }
837 QString smatched;
838 switch (p.parenmatch) {
839 case KLFLatexSyntaxHighlighter::ParsedBlock::None: smatched = "-"; break;
840 case KLFLatexSyntaxHighlighter::ParsedBlock::Matched: smatched = "Matched"; break;
841 case KLFLatexSyntaxHighlighter::ParsedBlock::Mismatched: smatched = "Mismatched"; break;
842 case KLFLatexSyntaxHighlighter::ParsedBlock::Lonely: smatched = "Lonely"; break;
843 default: smatched = "<error>"; break;
844 }
845 str << "ParsedBlock["<<stype.toLatin1()<<": "<<p.pos<<"+"<<p.len;
847 str << ", "<<p.keyword;
849 str << ", "<<smatched.toLatin1()<<(p.parenisopening?"(opening)":"(closing)")<<"#"<<p.parenSpecIndex<<" "
850 <<p.parenmodifier<<p.parenstr<<" otherpos="<<p.parenotherpos;
851 }
852 return str << "]";
853}
An abstract handler for when data is dropped.
Definition klfguiutil.h:527
@ OpenDataOk
Opened the data Ok.
Definition klfguiutil.h:530
@ OpenDataFailed
Could handle data format, but failed to open (no further processing)
Definition klfguiutil.h:531
A text edit field that edits latex code.
void setPalette(const QPalette &palette)
KLFLatexSyntaxHighlighter * syntaxHighlighter()
void setLatex(const QString &latex)
virtual ~KLFLatexEdit()
virtual void contextMenuEvent(QContextMenuEvent *event)
KLFLatexEdit(QWidget *parent)
virtual void insertFromMimeData(const QMimeData *source)
virtual QSize sizeHint() const
void setDropDataHandler(KLFDropDataHandler *handler)
void insertDelimiter(const QString &delim, int charsBack=1)
void setWrapLines(bool wrap)
void setHeightHintLines(int lines)
void insertContextMenuActions(const QPoint &pos, QList< QAction * > *actionList)
QString latex() const
virtual bool canInsertFromMimeData(const QMimeData *source) const
QStringList openParenList() const
QList< ParenModifierSpec > parenModifierSpecList() const
virtual ~KLFLatexParenSpecs()
QStringList openParenModifiers() const
QList< ParenSpec > parenSpecList() const
int identifyModifier(const QString &modstr, uint identflags)
@ IdentifyFlagClose
Identify the paren as closing only.
@ IdentifyFlagOpen
Identify the paren as opening only.
int identifyParen(const QString &parenstr, uint identflags)
QStringList closeParenModifiers() const
QStringList closeParenList() const
void setFmtParenMatch(const QTextFormat &f)
KLFLatexSyntaxHighlighter(QTextEdit *textedit, QObject *parent)
virtual void highlightBlock(const QString &text)
void setFmtKeyword(const QTextFormat &f)
void setFmtLonelyParen(const QTextFormat &f)
void setFmtParenMismatch(const QTextFormat &f)
void newSymbolTyped(const QString &symbolName)
void setCaretPos(int position)
QList< ParsedBlock > parsedBlocksForPos(int pos, unsigned int filter_type=0xffffffff) const
void setHighlightEnabled(bool on)
void setHighlightParensOnly(bool on)
void setFmtComment(const QTextFormat &f)
void setHighlightLonelyParens(bool on)
const char * format
const char * type
#define klfWarning(streamableItems)
Definition klfdebug.h:171
#define KLF_DEBUG_BLOCK(msg)
Utility to debug the execution of a block.
Definition klfdebug.h:152
#define KLF_ASSERT_CONDITION(expr, msg, failaction)
Asserting Conditions (NON-FATAL)
Definition klfdebug.h:201
#define klfDbg(streamableItems)
print debug stream items
Definition klfdebug.h:158
#define KLF_PRIVATE_HEAD(ClassName)
Definition klfdefs.h:81
#define klfFmtCC
Definition klfdefs.h:61
#define KLF_DELETE_PRIVATE
Definition klfdefs.h:96
#define KLF_EXPORT
Definition klfdefs.h:41
#define KLF_INIT_PRIVATE(ClassName)
Definition klfdefs.h:94
QDebug operator<<(QDebug str, const KLFLatexSyntaxHighlighter::ParsedBlock &p)
QList< T > klfListMap(const QList< T > &list, MapOp op)
Definition klfutil.h:452
void append(const T &value)
void clear()
iterator end()
int size() const
virtual QStringList formats() const
bool inherits(const char *className) const
QObject * parent() const
void setColor(ColorGroup group, ColorRole role, const QColor &color)
QString escape(const QString &str)
int width() const
void push(const T &t)
T & top()
QString & insert(int position, QChar ch)
bool isEmpty() const
int length() const
QString mid(int position, int n) const
int size() const
QByteArray toLatin1() const
bool contains(const QString &str, Qt::CaseSensitivity cs) const
QString join(const QString &separator) const
QTextBlock currentBlock() const
QTextDocument * document() const
void setDocument(QTextDocument *doc)
void setFormat(int start, int count, const QTextCharFormat &format)
bool isValid() const
int length() const
QTextBlock next() const
int position() const
QString text() const
void setFontItalic(bool italic)
void setFontWeight(int weight)
void beginEditBlock()
void endEditBlock()
void insertText(const QString &text)
bool movePosition(MoveOperation operation, MoveMode mode, int n)
void removeSelectedText()
void select(SelectionType selection)
QTextDocumentFragment selection() const
QTextBlock firstBlock() const
QTextBlock lastBlock() const
QString toPlainText() const
bool isCharFormat() const
void setBackground(const QBrush &brush)
void setForeground(const QBrush &brush)
QTextCharFormat toCharFormat() const
QVariant fromValue(const T &value)
QMap< QString, QVariant > toMap() const
bool empty() const
void resize(int size)
int size() const
static KLFLatexParenSpecs parenSpecs

Generated by doxygen 1.11.0