Added support to debug XSLT using xsldbg by Keith Isdale.
[kdbg.git] / kdbg / exprwnd.cpp
blob8111540475d94ddaf3b6e39bbc20f81662ee7a13
1 // $Id$
3 // Copyright by Johannes Sixt
4 // This file is under GPL, the GNU General Public Licence
6 #include "exprwnd.h"
7 #include "exprwnd.moc"
8 #include "typetable.h"
9 #include <qstrlist.h>
10 #include <qpainter.h>
11 #include <kapp.h>
12 #include <kiconloader.h> /* icons */
13 #ifdef HAVE_CONFIG_H
14 #include "config.h"
15 #endif
16 #include "mydebug.h"
18 VarTree::VarTree(const QString& name, NameKind aKind) :
19 KTreeViewItem(name),
20 m_varKind(VKsimple),
21 m_nameKind(aKind),
22 m_valueChanged(false),
23 m_type(0),
24 m_exprIndex(0),
25 m_exprIndexUseGuard(false)
29 VarTree::~VarTree()
33 void VarTree::paintValue(QPainter* p)
35 p->save();
36 int cellHeight = height(p->fontMetrics());
37 int textX = 2;
38 int textY = (cellHeight - p->fontMetrics().height()) / 2 +
39 p->fontMetrics().ascent();
41 if (m_valueChanged) {
42 p->setPen(red);
44 // p->setBackgroundColor(cg.base());
45 p->drawText(textX, textY, m_value, m_value.length());
46 p->restore();
49 int VarTree::valueWidth()
51 assert(owner != 0);
52 return owner->fontMetrics().width(m_value) + 4;
55 QString VarTree::computeExpr() const
57 assert(getParent() != 0);
58 // just to be sure
59 if (getParent() == 0)
60 return QString();
62 // top-level items are special
63 if (getParent()->getParent() == 0)
64 return getText();
66 // get parent expr
67 VarTree* par = static_cast<VarTree*>(getParent());
68 QString parentExpr = par->computeExpr();
70 /* don't add this item's name if this is a base class sub-item */
71 if (m_nameKind == NKtype) {
72 return parentExpr;
74 /* augment by this item's text */
75 QString result;
76 /* if this is an address, dereference it */
77 if (m_nameKind == NKaddress) {
78 ASSERT(par->m_varKind == VKpointer);
79 result = "*" + parentExpr;
80 return result;
82 switch (par->m_varKind) {
83 case VKarray:
85 QString index = getText();
86 int i = 1;
87 // skip past the index
88 while (index[i].isDigit())
89 i++;
91 * Some array indices are actually ranges due to repeated array
92 * values. We use the first index in these cases.
94 if (index[i] != ']') {
95 // remove second index
96 index.remove(i, index.length()-i-1);
98 result = "(" + parentExpr + ")" + index;
100 break;
101 case VKstruct:
102 result = "(" + parentExpr + ")." + getText();
103 break;
104 case VKsimple: /* parent can't be simple */
105 case VKpointer: /* handled in NKaddress */
106 case VKdummy: /* can't occur at all */
107 ASSERT(false);
108 result = parentExpr; /* paranoia */
109 break;
111 return result;
114 bool VarTree::isToplevelExpr() const
116 return getParent() != 0 && getParent()->getParent() == 0;
119 bool VarTree::isAncestorEq(const VarTree* child) const
121 const KTreeViewItem* c = child;
122 while (c != 0 && c != this) {
123 c = c->getParent();
125 return c != 0;
128 bool VarTree::updateValue(const QString& newValue)
130 // check whether the value changed
131 bool prevValueChanged = m_valueChanged;
132 m_valueChanged = false;
133 if (m_value != newValue) {
134 m_value = newValue;
135 m_valueChanged = true;
138 * We must repaint the cell if the value changed. If it did not change,
139 * we still must repaint the cell if the value changed previously,
140 * because the color of the display must be changed (from red to
141 * black).
143 return m_valueChanged || prevValueChanged;
146 void VarTree::inferTypesOfChildren(ProgramTypeTable& typeTable)
149 * Type inference works like this: We use type information of those
150 * children that have a type name in their name (base classes) or in
151 * their value (pointers)
154 // first recurse children
155 VarTree* child = static_cast<VarTree*>(getChild());
156 while (child != 0) {
157 child->inferTypesOfChildren(typeTable);
158 child = static_cast<VarTree*>(child->getSibling());
161 // if this is a pointer, get the type from the value (less the pointer)
162 if (m_varKind == VKpointer) {
163 #ifndef I_know_a_way_to_do_this_cleanly
164 return;
165 #else
166 const char* p = m_value.data();
167 const char* start = p;
168 // the type of the pointer shows up in the value (sometimes)
169 if (p == 0 || *p != '(')
170 return;
171 skipNested(p, '(', ')');
173 * We only recognize pointers to data "(int *)" but not pointers
174 * to functions "(void (*)())".
176 if (p-start < 3 && /* at least 3 chars necessary: (*) */
177 p[-2] != '*') /* skip back before the closing paren */
179 return;
181 const QString& typeName =
182 FROM_LATIN1(start+1, p-start-3) // minus 3 chars
183 .stripWhiteSpace();
184 m_type = typeTable.lookup(typeName);
185 if (m_type == 0) {
186 m_type = TypeInfo::unknownType();
188 #endif
189 } else if (m_varKind == VKstruct) {
190 // check if this is a base class part
191 if (m_nameKind == NKtype) {
192 const QString& typeName =
193 text.mid(1, text.length()-2); // strip < and >
194 m_type = typeTable.lookup(typeName);
196 /* if we don't have a type yet, get it from the base class */
197 if (m_type == 0) {
198 m_type = inferTypeFromBaseClass();
200 * If there is a known type now, it is the one from the
201 * first base class whose type we know.
206 * If we still don't have a type, the type is really unknown.
208 if (m_type == 0) {
209 m_type = TypeInfo::unknownType();
211 } // else
213 * This is not a base class part. We don't assign a type so
214 * that later we can ask gdb.
220 * Get the type of the first base class whose type we know.
222 TypeInfo* VarTree::inferTypeFromBaseClass()
224 if (m_varKind == VKstruct) {
225 VarTree* child = static_cast<VarTree*>(getChild());
226 while (child != 0 &&
227 // only check base class parts (i.e. type names)
228 child->m_nameKind == NKtype)
230 if (child->m_type != 0 &&
231 child->m_type != TypeInfo::unknownType())
233 // got a type!
234 return child->m_type;
236 child = static_cast<VarTree*>(child->getSibling());
239 return 0;
243 ExprWnd::ExprWnd(QWidget* parent, const char* name) :
244 KTreeView(parent, name),
245 maxValueWidth(0)
247 setNumCols(2);
249 connect(this, SIGNAL(expanded(int)), SLOT(slotExpandOrCollapse(int)));
250 connect(this, SIGNAL(collapsed(int)), SLOT(slotExpandOrCollapse(int)));
252 #if QT_VERSION < 200
253 KIconLoader* loader = kapp->getIconLoader();
254 m_pixPointer = loader->loadIcon("pointer.xpm");
255 #else
256 m_pixPointer = BarIcon("pointer.xpm");
257 #endif
258 if (m_pixPointer.isNull())
259 TRACE("Can't load pointer.xpm");
262 ExprWnd::~ExprWnd()
266 void ExprWnd::exprList(QStrList& exprs)
268 // ASSERT(exprs does deep-copies)
269 KTreeViewItem* item;
270 for (item = itemAt(0); item != 0; item = item->getSibling()) {
271 exprs.append(item->getText());
275 void ExprWnd::insertExpr(VarTree* expr)
277 // append the expression
278 insertItem(expr);
280 collectUnknownTypes(expr);
282 updateValuesWidth();
285 void ExprWnd::updateExpr(VarTree* expr)
287 // search the root variable
288 QString p = expr->getText();
289 KPath path;
290 path.push(&p);
291 KTreeViewItem* item = itemAt(path);
292 path.pop();
293 if (item == 0) {
294 return;
296 // now update it
297 if (updateExprRec(static_cast<VarTree*>(item), expr)) {
298 updateVisibleItems();
299 updateValuesWidth();
300 repaint();
302 collectUnknownTypes(static_cast<VarTree*>(item));
305 void ExprWnd::updateExpr(VarTree* display, VarTree* newValues)
307 if (updateExprRec(display, newValues) && display->isVisible()) {
308 updateVisibleItems();
309 updateValuesWidth();
310 repaint();
312 collectUnknownTypes(display);
316 * returns true if there's a visible change
318 bool ExprWnd::updateExprRec(VarTree* display, VarTree* newValues)
320 bool isExpanded = display->isExpanded();
323 * If we are updating a pointer without children by a dummy, we don't
324 * collapse it, but simply insert the new children. This happens when a
325 * pointer has just been expanded by the user.
327 if (display->m_varKind == VarTree::VKpointer &&
328 display->childCount() == 0 &&
329 newValues->m_varKind == VarTree::VKdummy)
331 replaceChildren(display, newValues);
332 return isExpanded; /* no visible change if not expanded */
336 * If the display and newValues have different kind or if their number
337 * of children is different, replace the whole sub-tree.
339 if (// the next two lines mean: not(m_varKind remains unchanged)
340 !(newValues->m_varKind == VarTree::VKdummy ||
341 display->m_varKind == newValues->m_varKind)
343 (display->childCount() != newValues->childCount() &&
345 * If this is a pointer and newValues doesn't have children, we
346 * don't replace the sub-tree; instead, below we mark this
347 * sub-tree for requiring an update.
349 (display->m_varKind != VarTree::VKpointer ||
350 newValues->childCount() != 0)))
352 if (isExpanded) {
353 collapseSubTree(display, false);
356 // since children changed, it is likely that the type has also changed
357 display->m_type = 0; /* will re-evaluate the type */
359 // display the new value
360 updateSingleExpr(display, newValues);
361 replaceChildren(display, newValues);
363 // update the m_varKind
364 if (newValues->m_varKind != VarTree::VKdummy) {
365 display->m_varKind = newValues->m_varKind;
366 display->setDelayedExpanding(newValues->m_varKind == VarTree::VKpointer);
369 // (note that the new value might not have a sub-tree at all)
370 return display->m_valueChanged || isExpanded; /* no visible change if not expanded */
373 // display the new value
374 updateSingleExpr(display, newValues);
377 * If this is an expanded pointer, record it for being updated.
379 if (display->m_varKind == VarTree::VKpointer) {
380 if (isExpanded &&
381 // if newValues is a dummy, we have already updated this pointer
382 newValues->m_varKind != VarTree::VKdummy)
384 m_updatePtrs.append(display);
387 * If the visible sub-tree has children, but newValues doesn't, we
388 * can stop here.
390 if (newValues->childCount() == 0) {
391 return display->m_valueChanged;
395 ASSERT(display->childCount() == newValues->childCount());
397 // go for children
398 bool childChanged = false;
400 VarTree* vDisplay = static_cast<VarTree*>(display->getChild());
401 VarTree* vNew = static_cast<VarTree*>(newValues->getChild());
402 while (vDisplay != 0) {
403 // check whether the names are the same
404 if (strcmp(vDisplay->getText(), vNew->getText()) != 0) {
405 // set new name
406 vDisplay->setText(vNew->getText());
407 int i = itemRow(vDisplay);
408 if (i >= 0) {
409 updateCell(i, 0, true);
410 childChanged = true;
413 // recurse
414 if (updateExprRec(vDisplay, vNew)) {
415 childChanged = true;
417 vDisplay = static_cast<VarTree*>(vDisplay->getSibling());
418 vNew = static_cast<VarTree*>(vNew->getSibling());
421 // update of children propagates only if this node is expanded
422 return display->m_valueChanged || (display->isExpanded() && childChanged);
425 void ExprWnd::updateSingleExpr(VarTree* display, VarTree* newValue)
428 * If newValues is a VKdummy, we are only interested in its children.
429 * No need to update anything here.
431 if (newValue->m_varKind == VarTree::VKdummy) {
432 return;
436 * If this node is a struct and we know its type then don't update its
437 * value now. This is a node for which we know how to find a nested
438 * value. So register the node for an update.
440 if (display->m_varKind == VarTree::VKstruct &&
441 display->m_type != 0 &&
442 display->m_type != TypeInfo::unknownType())
444 ASSERT(newValue->m_varKind == VarTree::VKstruct);
445 display->m_partialValue = display->m_type->m_displayString[0];
446 m_updateStruct.append(display);
448 else
450 if (display->updateValue(newValue->m_value)) {
451 int i = itemRow(display);
452 if (i >= 0) {
453 updateCell(i, 1, true);
459 void ExprWnd::updateStructValue(VarTree* display)
461 ASSERT(display->m_varKind == VarTree::VKstruct);
463 if (display->updateValue(display->m_partialValue)) {
464 int i = itemRow(display);
465 if (i >= 0) {
466 updateValuesWidth();
467 updateCell(i, 1, true);
470 // reset the value
471 display->m_partialValue = "";
472 display->m_exprIndex = -1;
475 void ExprWnd::replaceChildren(VarTree* display, VarTree* newValues)
477 ASSERT(display->childCount() == 0 || display->m_varKind != VarTree::VKsimple);
479 // delete all children of display
480 KTreeViewItem* c;
481 while ((c = display->getChild()) != 0) {
482 display->removeChild(c);
484 // insert copies of the newValues
485 for (c = newValues->getChild(); c != 0; c = c->getSibling()) {
486 VarTree* v = static_cast<VarTree*>(c);
487 VarTree* vNew = new VarTree(v->getText(), v->m_nameKind);
488 vNew->m_varKind = v->m_varKind;
489 vNew->m_value = v->m_value;
490 vNew->m_type = v->m_type;
491 vNew->setDelayedExpanding(vNew->m_varKind == VarTree::VKpointer);
492 display->appendChild(vNew);
493 // recurse
494 replaceChildren(vNew, v);
498 void ExprWnd::collectUnknownTypes(VarTree* var)
501 * forEveryItem does not scan the root item itself. So we must do it
502 * ourselves.
504 ASSERT(var->m_varKind != VarTree::VKpointer || var->m_nameKind != VarTree::NKtype);
505 if (var->m_type == 0 &&
506 var->m_varKind == VarTree::VKstruct &&
507 var->m_nameKind != VarTree::NKtype)
509 /* this struct node doesn't have a type yet: register it */
510 m_updateType.append(var);
513 // add pointer pixmap to pointers
514 if (var->m_varKind == VarTree::VKpointer) {
515 var->setPixmap(m_pixPointer);
518 forEveryItem(collectUnknownTypes, this, var);
521 bool ExprWnd::collectUnknownTypes(KTreeViewItem* item, void* user)
523 VarTree* var = static_cast<VarTree*>(item);
524 ExprWnd* tree = static_cast<ExprWnd*>(user);
525 ASSERT(var->m_varKind != VarTree::VKpointer || var->m_nameKind != VarTree::NKtype);
526 if (var->m_type == 0 &&
527 var->m_varKind == VarTree::VKstruct &&
528 var->m_nameKind != VarTree::NKtype)
530 /* this struct node doesn't have a type yet: register it */
531 tree->m_updateType.append(var);
533 // add pointer pixmap to pointers
534 if (var->m_varKind == VarTree::VKpointer) {
535 var->setPixmap(tree->m_pixPointer);
537 return false;
541 VarTree* ExprWnd::topLevelExprByName(const char* name)
543 QString p = name;
544 KPath path;
545 path.push(&p);
546 KTreeViewItem* item = itemAt(path);
547 path.pop();
549 return static_cast<VarTree*>(item);
552 void ExprWnd::removeExpr(VarTree* item)
554 // must remove any pointers scheduled for update from the list
555 sweepList(m_updatePtrs, item);
556 sweepList(m_updateType, item);
557 sweepList(m_updateStruct, item);
559 takeItem(item);
560 delete item;
562 updateValuesWidth();
565 void ExprWnd::sweepList(QList<VarTree>& list, VarTree* subTree)
567 if (subTree == 0)
568 return;
570 VarTree* checkItem = list.first();
571 while (checkItem != 0) {
572 if (!subTree->isAncestorEq(checkItem)) {
573 // checkItem is not an item from subTree
574 // advance
575 checkItem = list.next();
576 } else {
577 // checkItem is an item from subTree
579 * If checkItem is the last item in the list, we need a special
580 * treatment, because remove()ing it steps the current item of
581 * the list in the "wrong" direction.
583 if (checkItem == list.getLast()) { // does not set current item
584 list.remove();
585 /* we deleted the last element, so we've finished */
586 checkItem = 0;
587 } else {
588 list.remove();
589 /* remove() advanced already */
590 checkItem = list.current();
596 QString ExprWnd::exprStringAt(int index)
598 KTreeViewItem* item = itemAt(index);
599 if (item == 0) return QString(); /* paranoia */
600 VarTree* expr = static_cast<VarTree*>(item);
601 return expr->computeExpr();
604 void ExprWnd::clearPendingUpdates()
606 m_updatePtrs.clear();
607 m_updateType.clear();
608 m_updateStruct.clear();
611 VarTree* ExprWnd::nextUpdatePtr()
613 VarTree* ptr = m_updatePtrs.first();
614 if (ptr != 0) {
615 m_updatePtrs.remove();
617 return ptr;
620 VarTree* ExprWnd::nextUpdateType()
622 VarTree* ptr = m_updateType.first();
623 if (ptr != 0) {
624 m_updateType.remove();
626 return ptr;
629 VarTree* ExprWnd::nextUpdateStruct()
631 VarTree* ptr = m_updateStruct.first();
632 if (ptr != 0) {
633 m_updateStruct.remove();
635 return ptr;
638 void ExprWnd::paintCell(QPainter* painter, int row, int col)
640 if (col == 0) {
641 KTreeView::paintCell(painter, row, col);
642 } else {
643 VarTree* item = static_cast<VarTree*>(itemAt(row));
644 if (item != 0) {
645 item->paintValue(painter);
650 int ExprWnd::cellWidth(int col) const
652 if (col == 0) {
653 return KTreeView::cellWidth(col);
654 } else {
655 return maxValueWidth;
659 void ExprWnd::updateValuesWidth()
661 int maxW = 0;
662 forEveryVisibleItem(static_cast<KForEveryFunc>(&getMaxValueWidth), &maxW);
663 maxValueWidth = maxW;
664 updateTableSize();
667 // called by updateValuesWidth() for each item in the visible list
668 bool ExprWnd::getMaxValueWidth(KTreeViewItem* item, void* user)
670 int *maxW = (int *)user;
671 VarTree* v = static_cast<VarTree*>(item);
672 int w = v->valueWidth();
673 if(w > *maxW)
674 *maxW = w;
675 return false;
678 void ExprWnd::slotExpandOrCollapse(int)
680 updateValuesWidth();