Convert from Qt 3 to Qt 4 using qt3to4.
[kdbg.git] / kdbg / sourcewnd.cpp
blob0b10a60de158a92d3256c6dc6c844a15331bacb2
1 /*
2 * Copyright Johannes Sixt
3 * This file is licensed under the GNU General Public License Version 2.
4 * See the file COPYING in the toplevel directory of the source directory.
5 */
7 #include "debugger.h"
8 #include "sourcewnd.h"
9 #include <q3textstream.h>
10 #include <qpainter.h>
11 #include <qbrush.h>
12 #include <qfile.h>
13 #include <qfileinfo.h>
14 #include <qnamespace.h>
15 #include <q3popupmenu.h>
16 #include <QContextMenuEvent>
17 #include <QKeyEvent>
18 #include <QMouseEvent>
19 #include <QEvent>
20 #include <kapplication.h>
21 #include <kiconloader.h>
22 #include <kglobalsettings.h>
23 #include <kmainwindow.h>
24 #include <algorithm>
25 #include "mydebug.h"
28 SourceWindow::SourceWindow(const QString& fileName, QWidget* parent) :
29 Q3TextEdit(parent),
30 m_fileName(fileName),
31 m_curRow(-1),
32 m_widthItems(16),
33 m_widthPlus(12),
34 m_widthLineNo(30)
36 // load pixmaps
37 m_pcinner = UserIcon("pcinner");
38 m_pcup = UserIcon("pcup");
39 m_brkena = UserIcon("brkena");
40 m_brkdis = UserIcon("brkdis");
41 m_brktmp = UserIcon("brktmp");
42 m_brkcond = UserIcon("brkcond");
43 m_brkorph = UserIcon("brkorph");
44 setFont(KGlobalSettings::fixedFont());
45 setReadOnly(true);
46 setMargins(m_widthItems+m_widthPlus+m_widthLineNo, 0, 0 ,0);
47 setAutoFormatting(AutoNone);
48 setTextFormat(Qt::PlainText);
49 setWordWrap(NoWrap);
50 connect(verticalScrollBar(), SIGNAL(valueChanged(int)),
51 this, SLOT(update()));
52 connect(this, SIGNAL(cursorPositionChanged(int,int)), this, SLOT(cursorChanged(int)));
53 viewport()->installEventFilter(this);
55 // add a syntax highlighter
56 if (QRegExp("\\.(c(pp|c|\\+\\+)?|CC?|h(\\+\\+|h)?|HH?)$").search(m_fileName) >= 0)
58 new HighlightCpp(this);
62 SourceWindow::~SourceWindow()
64 delete syntaxHighlighter();
67 bool SourceWindow::loadFile()
69 // first we load the code into QTextEdit
70 QFile f(m_fileName);
71 if (!f.open(QIODevice::ReadOnly)) {
72 return false;
75 Q3TextStream t(&f);
76 setText(t.read());
77 f.close();
79 // then we copy it into our own m_sourceCode
80 int n = paragraphs();
81 m_sourceCode.resize(n);
82 m_rowToLine.resize(n);
83 for (int i = 0; i < n; i++) {
84 m_sourceCode[i].code = text(i);
85 m_rowToLine[i] = i;
87 m_lineItems.resize(n, 0);
89 // set a font for line numbers
90 m_lineNoFont = currentFont();
91 m_lineNoFont.setPixelSize(11);
93 return true;
96 void SourceWindow::reloadFile()
98 QFile f(m_fileName);
99 if (!f.open(QIODevice::ReadOnly)) {
100 // open failed; leave alone
101 return;
104 // read text into m_sourceCode
105 m_sourceCode.clear(); /* clear old text */
107 Q3TextStream t(&f);
108 setText(t.read());
109 f.close();
111 m_sourceCode.resize(paragraphs());
112 for (size_t i = 0; i < m_sourceCode.size(); i++) {
113 m_sourceCode[i].code = text(i);
115 // expanded lines are collapsed: move existing line items up
116 for (size_t i = 0; i < m_lineItems.size(); i++) {
117 if (m_rowToLine[i] != i) {
118 m_lineItems[m_rowToLine[i]] |= m_lineItems[i];
119 m_lineItems[i] = 0;
122 // allocate line items
123 m_lineItems.resize(m_sourceCode.size(), 0);
125 m_rowToLine.resize(m_sourceCode.size());
126 for (size_t i = 0; i < m_sourceCode.size(); i++)
127 m_rowToLine[i] = i;
129 // Highlighting was applied above when the text was inserted into widget,
130 // but at that time m_rowToLine was not corrected, yet, so that lines
131 // that previously were assembly were painted incorrectly.
132 if (syntaxHighlighter())
133 syntaxHighlighter()->rehighlight();
134 update(); // line numbers
137 void SourceWindow::scrollTo(int lineNo, const DbgAddr& address)
139 if (lineNo < 0 || lineNo >= int(m_sourceCode.size()))
140 return;
142 int row = lineToRow(lineNo, address);
143 scrollToRow(row);
146 void SourceWindow::scrollToRow(int row)
148 setCursorPosition(row, 0);
149 ensureCursorVisible();
152 void SourceWindow::drawFrame(QPainter* p)
154 Q3TextEdit::drawFrame(p);
156 // and paragraph at the top is...
157 int top = paragraphAt(QPoint(0,contentsY()));
158 int bot = paragraphAt(QPoint(0,contentsY()+visibleHeight()-1));
159 if (bot < 0)
160 bot = paragraphs()-1;
162 p->save();
164 // set a clip rectangle
165 int fw = frameWidth();
166 QRect inside = rect();
167 inside.addCoords(fw,fw,-fw,-fw);
168 QRegion clip = p->clipRegion();
169 clip &= QRegion(inside);
170 p->setClipRegion(clip);
172 p->setFont(m_lineNoFont);
173 p->setPen(colorGroup().text());
174 p->eraseRect(inside);
176 for (int row = top; row <= bot; row++)
178 uchar item = m_lineItems[row];
179 p->save();
181 QRect r = paragraphRect(row);
182 QPoint pt = contentsToViewport(r.topLeft());
183 int h = r.height();
184 p->translate(fw, pt.y()+viewport()->y());
186 if (item & liBP) {
187 // enabled breakpoint
188 int y = (h - m_brkena.height())/2;
189 if (y < 0) y = 0;
190 p->drawPixmap(0,y,m_brkena);
192 if (item & liBPdisabled) {
193 // disabled breakpoint
194 int y = (h - m_brkdis.height())/2;
195 if (y < 0) y = 0;
196 p->drawPixmap(0,y,m_brkdis);
198 if (item & liBPtemporary) {
199 // temporary breakpoint marker
200 int y = (h - m_brktmp.height())/2;
201 if (y < 0) y = 0;
202 p->drawPixmap(0,y,m_brktmp);
204 if (item & liBPconditional) {
205 // conditional breakpoint marker
206 int y = (h - m_brkcond.height())/2;
207 if (y < 0) y = 0;
208 p->drawPixmap(0,y,m_brkcond);
210 if (item & liBPorphan) {
211 // orphaned breakpoint marker
212 int y = (h - m_brkcond.height())/2;
213 if (y < 0) y = 0;
214 p->drawPixmap(0,y,m_brkorph);
216 if (item & liPC) {
217 // program counter in innermost frame
218 int y = (h - m_pcinner.height())/2;
219 if (y < 0) y = 0;
220 p->drawPixmap(0,y,m_pcinner);
222 if (item & liPCup) {
223 // program counter somewhere up the stack
224 int y = (h - m_pcup.height())/2;
225 if (y < 0) y = 0;
226 p->drawPixmap(0,y,m_pcup);
228 p->translate(m_widthItems, 0);
229 if (!isRowDisassCode(row) && m_sourceCode[rowToLine(row)].canDisass) {
230 int w = m_widthPlus;
231 int x = w/2;
232 int y = h/2;
233 p->drawLine(x-2, y, x+2, y);
234 if (!isRowExpanded(row)) {
235 p->drawLine(x, y-2, x, y+2);
238 p->translate(m_widthPlus, 0);
239 if (!isRowDisassCode(row)) {
240 p->drawText(0, 0, m_widthLineNo, h, Qt::AlignRight|Qt::AlignVCenter,
241 QString().setNum(rowToLine(row)+1));
243 p->restore();
245 p->restore();
248 void SourceWindow::updateLineItems(const KDebugger* dbg)
250 // clear outdated breakpoints
251 for (int i = m_lineItems.size()-1; i >= 0; i--) {
252 if (m_lineItems[i] & liBPany) {
253 // check if this breakpoint still exists
254 int line = rowToLine(i);
255 TRACE(QString().sprintf("checking for bp at %d", line));
256 KDebugger::BrkptROIterator bp = dbg->breakpointsBegin();
257 for (; bp != dbg->breakpointsEnd(); ++bp)
259 if (bp->lineNo == line &&
260 fileNameMatches(bp->fileName) &&
261 lineToRow(line, bp->address) == i)
263 // yes it exists; mode is changed below
264 break;
267 if (bp == dbg->breakpointsEnd()) {
268 /* doesn't exist anymore, remove it */
269 m_lineItems[i] &= ~liBPany;
270 update();
275 // add new breakpoints
276 for (KDebugger::BrkptROIterator bp = dbg->breakpointsBegin(); bp != dbg->breakpointsEnd(); ++bp)
278 if (fileNameMatches(bp->fileName)) {
279 TRACE(QString().sprintf("updating %s:%d", bp->fileName.data(), bp->lineNo));
280 int i = bp->lineNo;
281 if (i < 0 || i >= int(m_sourceCode.size()))
282 continue;
283 // compute new line item flags for breakpoint
284 uchar flags = bp->enabled ? liBP : liBPdisabled;
285 if (bp->temporary)
286 flags |= liBPtemporary;
287 if (!bp->condition.isEmpty() || bp->ignoreCount != 0)
288 flags |= liBPconditional;
289 if (bp->isOrphaned())
290 flags |= liBPorphan;
291 // update if changed
292 int row = lineToRow(i, bp->address);
293 if ((m_lineItems[row] & liBPany) != flags) {
294 m_lineItems[row] &= ~liBPany;
295 m_lineItems[row] |= flags;
296 update();
302 void SourceWindow::setPC(bool set, int lineNo, const DbgAddr& address, int frameNo)
304 if (lineNo < 0 || lineNo >= int(m_sourceCode.size())) {
305 return;
308 int row = lineToRow(lineNo, address);
310 uchar flag = frameNo == 0 ? liPC : liPCup;
311 if (set) {
312 // set only if not already set
313 if ((m_lineItems[row] & flag) == 0) {
314 m_lineItems[row] |= flag;
315 update();
317 } else {
318 // clear only if not set
319 if ((m_lineItems[row] & flag) != 0) {
320 m_lineItems[row] &= ~flag;
321 update();
326 void SourceWindow::find(const QString& text, bool caseSensitive, FindDirection dir)
328 ASSERT(dir == 1 || dir == -1);
329 if (Q3TextEdit::find(text, caseSensitive, false, dir > 0))
330 return;
331 // not found; wrap around
332 int para = dir > 0 ? 0 : paragraphs(), index = 0;
333 Q3TextEdit::find(text, caseSensitive, false, dir > 0, &para, &index);
336 void SourceWindow::mousePressEvent(QMouseEvent* ev)
338 // we handle left and middle button
339 if (ev->button() != Qt::LeftButton && ev->button() != Qt::MidButton)
341 Q3TextEdit::mousePressEvent(ev);
342 return;
345 // get row
346 QPoint p = viewportToContents(QPoint(0, ev->y() - viewport()->y()));
347 int row = paragraphAt(p);
348 if (row < 0)
349 return;
351 if (ev->x() > m_widthItems+frameWidth())
353 if (isRowExpanded(row)) {
354 actionCollapseRow(row);
355 } else {
356 actionExpandRow(row);
358 return;
361 int sourceRow;
362 int line = rowToLine(row, &sourceRow);
364 // find address if row is disassembled code
365 DbgAddr address;
366 if (row > sourceRow) {
367 // get offset from source code line
368 int off = row - sourceRow;
369 address = m_sourceCode[line].disassAddr[off-1];
372 switch (ev->button()) {
373 case Qt::LeftButton:
374 TRACE(QString().sprintf("left-clicked line %d", line));
375 emit clickedLeft(m_fileName, line, address,
376 (ev->state() & Qt::ShiftButton) != 0);
377 break;
378 case Qt::MidButton:
379 TRACE(QString().sprintf("mid-clicked row %d", line));
380 emit clickedMid(m_fileName, line, address);
381 break;
382 default:;
386 void SourceWindow::keyPressEvent(QKeyEvent* ev)
388 int top1, top2;
389 QPoint top;
390 switch (ev->key()) {
391 case Qt::Key_Plus:
392 actionExpandRow(m_curRow);
393 return;
394 case Qt::Key_Minus:
395 actionCollapseRow(m_curRow);
396 return;
397 case Qt::Key_Up:
398 if (m_curRow > 0) {
399 setCursorPosition(m_curRow-1, 0);
401 return;
402 case Qt::Key_Down:
403 if (m_curRow < paragraphs()-1) {
404 setCursorPosition(m_curRow+1, 0);
406 return;
407 case Qt::Key_Home:
408 setCursorPosition(0, 0);
409 return;
410 case Qt::Key_End:
411 setCursorPosition(paragraphs()-1, 0);
412 return;
413 case Qt::Key_Next:
414 case Qt::Key_Prior:
415 top = viewportToContents(QPoint(0,0));
416 top1 = paragraphAt(top);
419 Q3TextEdit::keyPressEvent(ev);
421 switch (ev->key()) {
422 case Qt::Key_Next:
423 case Qt::Key_Prior:
424 top = viewportToContents(QPoint(0,0));
425 top2 = paragraphAt(top);
426 setCursorPosition(m_curRow+(top2-top1), 0);
430 static inline bool isident(QChar c)
432 return c.isLetterOrNumber() || c.latin1() == '_';
435 bool SourceWindow::wordAtPoint(const QPoint& p, QString& word, QRect& r)
437 QPoint pv = viewportToContents(p - viewport()->pos());
438 int row, col = charAt(pv, &row);
439 if (row < 0 || col < 0)
440 return false;
442 // isolate the word at row, col
443 QString line = text(row);
444 if (!isident(line[col]))
445 return false;
447 int begin = col;
448 while (begin > 0 && isident(line[begin-1]))
449 --begin;
451 ++col;
452 while (col < int(line.length()) && isident(line[col]));
454 r = QRect(p, p);
455 r.addCoords(-5,-5,5,5);
456 word = line.mid(begin, col-begin);
457 return true;
460 void SourceWindow::paletteChange(const QPalette& oldPal)
462 setFont(KGlobalSettings::fixedFont());
463 Q3TextEdit::paletteChange(oldPal);
467 * Two file names (possibly full paths) match if the last parts - the file
468 * names - match.
470 bool SourceWindow::fileNameMatches(const QString& other)
472 return QFileInfo(other).fileName() == QFileInfo(m_fileName).fileName();
475 void SourceWindow::disassembled(int lineNo, const std::list<DisassembledCode>& disass)
477 TRACE("disassembled line " + QString().setNum(lineNo));
478 if (lineNo < 0 || lineNo >= int(m_sourceCode.size()))
479 return;
481 SourceLine& sl = m_sourceCode[lineNo];
483 // copy disassembled code and its addresses
484 sl.disass.resize(disass.size());
485 sl.disassAddr.resize(disass.size());
486 sl.canDisass = !disass.empty();
487 int i = 0;
488 for (std::list<DisassembledCode>::const_iterator c = disass.begin(); c != disass.end(); ++c, ++i)
490 QString code = c->code;
491 while (code.endsWith("\n"))
492 code.truncate(code.length()-1);
493 sl.disass[i] = c->address.asString() + ' ' + code;
494 sl.disassAddr[i] = c->address;
497 int row = lineToRow(lineNo);
498 if (sl.canDisass) {
499 expandRow(row);
500 } else {
501 // clear expansion marker
502 update();
506 int SourceWindow::rowToLine(int row, int* sourceRow)
508 int line = row >= 0 ? m_rowToLine[row] : -1;
509 if (sourceRow != 0) {
510 // search back until we hit the first entry with the current line number
511 while (row > 0 && m_rowToLine[row-1] == line)
512 row--;
513 *sourceRow = row;
515 return line;
519 * Rows showing diassembled code have the same line number as the
520 * corresponding source code line number. Therefore, the line numbers in
521 * m_rowToLine are monotonically increasing with blocks of equal line
522 * numbers for a source line and its disassembled code that follows it.
524 * Hence, m_rowToLine always obeys the following condition:
526 * m_rowToLine[i] <= i
529 int SourceWindow::lineToRow(int line)
531 // line is zero-based!
533 assert(line < int(m_rowToLine.size()));
535 // quick test for common case
536 if (line < 0 || m_rowToLine[line] == line)
537 return line;
539 assert(m_rowToLine[line] < line);
542 * Binary search between row == line and end of list. In the loop below
543 * we use the fact that the line numbers m_rowToLine do not contain
544 * holes.
546 int l = line;
547 int h = m_rowToLine.size();
548 while (l < h && m_rowToLine[l] != line)
550 assert(h == int(m_rowToLine.size()) || m_rowToLine[l] < m_rowToLine[h]);
553 * We want to round down the midpoint so that we find the
554 * lowest row that belongs to the line we seek.
556 int mid = (l+h)/2;
557 if (m_rowToLine[mid] <= line)
558 l = mid;
559 else
560 h = mid;
562 // Found! Result is in l:
563 assert(m_rowToLine[l] == line);
566 * We might not have hit the lowest index for the line.
568 while (l > 0 && m_rowToLine[l-1] == line)
569 --l;
571 return l;
574 int SourceWindow::lineToRow(int line, const DbgAddr& address)
576 int row = lineToRow(line);
577 if (isRowExpanded(row)) {
578 row += m_sourceCode[line].findAddressRowOffset(address);
580 return row;
583 bool SourceWindow::isRowExpanded(int row)
585 assert(row >= 0);
586 return row < int(m_rowToLine.size())-1 &&
587 m_rowToLine[row] == m_rowToLine[row+1];
590 bool SourceWindow::isRowDisassCode(int row)
592 return row > 0 && row < int(m_rowToLine.size()) &&
593 m_rowToLine[row] == m_rowToLine[row-1];
596 void SourceWindow::expandRow(int row)
598 TRACE("expanding row " + QString().setNum(row));
599 // get disassembled code
600 int line = rowToLine(row);
601 const std::vector<QString>& disass = m_sourceCode[line].disass;
603 // remove PC (must be set again in slot of signal expanded())
604 m_lineItems[row] &= ~(liPC|liPCup);
606 // adjust current row
607 if (m_curRow > row) {
608 m_curRow += disass.size();
609 // highlight is moved automatically
612 // insert new lines
613 setUpdatesEnabled(false);
614 ++row;
615 for (size_t i = 0; i < disass.size(); i++) {
616 m_rowToLine.insert(m_rowToLine.begin()+row, line);
617 m_lineItems.insert(m_lineItems.begin()+row, 0);
618 insertParagraph(disass[i], row++);
620 setUpdatesEnabled(true);
621 viewport()->update();
622 update(); // line items
624 emit expanded(line); /* must set PC */
627 void SourceWindow::collapseRow(int row)
629 TRACE("collapsing row " + QString().setNum(row));
630 int line = rowToLine(row);
632 // find end of this block
633 int end = row+1;
634 while (end < int(m_rowToLine.size()) && m_rowToLine[end] == m_rowToLine[row]) {
635 end++;
637 ++row;
638 // adjust current row
639 if (m_curRow >= row) {
640 m_curRow -= end-row;
641 if (m_curRow < row) // was m_curRow in disassembled code?
642 m_curRow = -1;
644 setUpdatesEnabled(false);
645 while (--end >= row) {
646 m_rowToLine.erase(m_rowToLine.begin()+end);
647 m_lineItems.erase(m_lineItems.begin()+end);
648 removeParagraph(end);
650 setUpdatesEnabled(true);
651 viewport()->update();
652 update(); // line items
654 emit collapsed(line);
657 void SourceWindow::activeLine(int& line, DbgAddr& address)
659 int row = m_curRow;
661 int sourceRow;
662 line = rowToLine(row, &sourceRow);
663 if (row > sourceRow) {
664 int off = row - sourceRow; /* offset from source line */
665 address = m_sourceCode[line].disassAddr[off-1];
670 * Returns the offset from the line displaying the source code to
671 * the line containing the specified address. If the address is not
672 * found, 0 is returned.
674 int SourceWindow::SourceLine::findAddressRowOffset(const DbgAddr& address) const
676 if (address.isEmpty())
677 return 0;
679 for (size_t i = 0; i < disassAddr.size(); i++) {
680 if (disassAddr[i] == address) {
681 // found exact address
682 return i+1;
684 if (disassAddr[i] > address) {
686 * We have already advanced too far; the address is before this
687 * index, but obviously we haven't found an exact match
688 * earlier. address is somewhere between the displayed
689 * addresses. We return the previous line.
691 return i;
694 // not found
695 return 0;
698 void SourceWindow::actionExpandRow(int row)
700 if (row < 0 || isRowExpanded(row) || isRowDisassCode(row))
701 return;
703 // disassemble
704 int line = rowToLine(row);
705 const SourceLine& sl = m_sourceCode[line];
706 if (!sl.canDisass)
707 return;
708 if (sl.disass.size() == 0) {
709 emit disassemble(m_fileName, line);
710 } else {
711 expandRow(row);
715 void SourceWindow::actionCollapseRow(int row)
717 if (row < 0 || !isRowExpanded(row) || isRowDisassCode(row))
718 return;
720 collapseRow(row);
723 void SourceWindow::setTabWidth(int numChars)
725 if (numChars <= 0)
726 numChars = 8;
727 QFontMetrics fm(currentFont());
728 QString s;
729 int w = fm.width(s.fill('x', numChars));
730 setTabStopWidth(w);
733 void SourceWindow::cursorChanged(int row)
735 if (row == m_curRow)
736 return;
738 if (m_curRow >= 0 && m_curRow < paragraphs())
739 clearParagraphBackground(m_curRow);
740 m_curRow = row;
741 setParagraphBackgroundColor(row, colorGroup().background());
745 * We must override the context menu handling because QTextEdit's handling
746 * requires that it receives ownership of the popup menu; but the popup menu
747 * returned from the GUI factory is owned by the factory.
750 void SourceWindow::contextMenuEvent(QContextMenuEvent* e)
752 // get the context menu from the GUI factory
753 QWidget* top = this;
755 top = top->parentWidget();
756 while (!top->isTopLevel());
757 KMainWindow* mw = static_cast<KMainWindow*>(top);
758 Q3PopupMenu* m =
759 static_cast<Q3PopupMenu*>(mw->factory()->container("popup_files", mw));
760 m->exec(e->globalPos());
763 bool SourceWindow::eventFilter(QObject* watched, QEvent* e)
765 if (e->type() == QEvent::ContextMenu && watched == viewport())
767 contextMenuEvent(static_cast<QContextMenuEvent*>(e));
768 return true;
770 return Q3TextEdit::eventFilter(watched, e);
773 HighlightCpp::HighlightCpp(SourceWindow* srcWnd) :
774 Q3SyntaxHighlighter(srcWnd),
775 m_srcWnd(srcWnd)
779 enum HLState {
780 hlCommentLine = 1,
781 hlCommentBlock,
782 hlIdent,
783 hlString
786 static const QString ckw[] =
788 "and",
789 "and_eq",
790 "asm",
791 "auto",
792 "bitand",
793 "bitor",
794 "bool",
795 "break",
796 "case",
797 "catch",
798 "char",
799 "class",
800 "compl",
801 "const",
802 "const_cast",
803 "continue",
804 "default",
805 "delete",
806 "do",
807 "double",
808 "dynamic_cast",
809 "else",
810 "enum",
811 "explicit",
812 "export",
813 "extern",
814 "false",
815 "float",
816 "for",
817 "friend",
818 "goto",
819 "if",
820 "inline",
821 "int",
822 "long",
823 "mutable",
824 "namespace",
825 "new",
826 "not",
827 "not_eq",
828 "operator",
829 "or",
830 "or_eq",
831 "private",
832 "protected",
833 "public",
834 "reinterpret_cast",
835 "register",
836 "return",
837 "short",
838 "signed",
839 "sizeof",
840 "static",
841 "static_cast",
842 "struct",
843 "switch",
844 "template",
845 "this",
846 "throw",
847 "true",
848 "try",
849 "typedef",
850 "typeid",
851 "typename",
852 "using",
853 "union",
854 "unsigned",
855 "virtual",
856 "void",
857 "volatile",
858 "wchar_t",
859 "while",
860 "xor",
861 "xor_eq"
864 int HighlightCpp::highlightParagraph(const QString& text, int state)
866 int row = currentParagraph();
867 // highlight assembly lines
868 if (m_srcWnd->isRowDisassCode(row))
870 setFormat(0, text.length(), Qt::blue);
871 return state;
874 if (state == -2) // initial state
875 state = 0;
877 // check for preprocessor line
878 if (state == 0 && text.stripWhiteSpace().startsWith("#"))
880 setFormat(0, text.length(), QColor("dark green"));
881 return 0;
884 // a font for keywords
885 QFont identFont = textEdit()->currentFont();
886 identFont.setBold(!identFont.bold());
888 unsigned start = 0;
889 while (start < text.length())
891 int end;
892 switch (state) {
893 case hlCommentLine:
894 end = text.length();
895 state = 0;
896 setFormat(start, end-start, QColor("gray50"));
897 break;
898 case hlCommentBlock:
899 end = text.find("*/", start);
900 if (end >= 0)
901 end += 2, state = 0;
902 else
903 end = text.length();
904 setFormat(start, end-start, QColor("gray50"));
905 break;
906 case hlString:
907 for (end = start+1; end < int(text.length()); end++) {
908 if (text[end] == '\\') {
909 if (end < int(text.length()))
910 ++end;
911 } else if (text[end] == text[start]) {
912 ++end;
913 break;
916 state = 0;
917 setFormat(start, end-start, QColor("dark red"));
918 break;
919 case hlIdent:
920 for (end = start+1; end < int(text.length()); end++) {
921 if (!text[end].isLetterOrNumber() && text[end] != '_')
922 break;
924 state = 0;
925 if (std::binary_search(ckw, ckw + sizeof(ckw)/sizeof(ckw[0]),
926 text.mid(start, end-start)))
928 setFormat(start, end-start, identFont);
929 } else {
930 setFormat(start, end-start, m_srcWnd->colorGroup().text());
932 break;
933 default:
934 for (end = start; end < int(text.length()); end++)
936 if (text[end] == '/')
938 if (end+1 < int(text.length())) {
939 if (text[end+1] == '/') {
940 state = hlCommentLine;
941 break;
942 } else if (text[end+1] == '*') {
943 state = hlCommentBlock;
944 break;
948 else if (text[end] == '"' || text[end] == '\'')
950 state = hlString;
951 break;
953 else if (text[end] >= 'A' && text[end] <= 'Z' ||
954 text[end] >= 'a' && text[end] <= 'z' ||
955 text[end] == '_')
957 state = hlIdent;
958 break;
961 setFormat(start, end-start, m_srcWnd->colorGroup().text());
963 start = end;
965 return state;
968 #include "sourcewnd.moc"