[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{
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{
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{
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{
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{
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 KLF_FUNC_NAME
Definition klfdebug.h:194
#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 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
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.9.8