When an item having the current item is taken out from the tree,
[kdbg.git] / kdbg / exprwnd.cpp
blob73c781cbe2b047ad0cfd86f9834a94a4c7ae00ad
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:
84 result = "(" + parentExpr + ")" + getText();
85 break;
86 case VKstruct:
87 result = "(" + parentExpr + ")." + getText();
88 break;
89 case VKsimple: /* parent can't be simple */
90 case VKpointer: /* handled in NKaddress */
91 case VKdummy: /* can't occur at all */
92 ASSERT(false);
93 result = parentExpr; /* paranoia */
94 break;
96 return result;
99 bool VarTree::isToplevelExpr() const
101 return getParent() != 0 && getParent()->getParent() == 0;
104 bool VarTree::isAncestorEq(const VarTree* child) const
106 const KTreeViewItem* c = child;
107 while (c != 0 && c != this) {
108 c = c->getParent();
110 return c != 0;
113 bool VarTree::updateValue(const QString& newValue)
115 // check whether the value changed
116 bool prevValueChanged = m_valueChanged;
117 m_valueChanged = false;
118 if (m_value != newValue) {
119 m_value = newValue;
120 m_valueChanged = true;
123 * We must repaint the cell if the value changed. If it did not change,
124 * we still must repaint the cell if the value changed previously,
125 * because the color of the display must be changed (from red to
126 * black).
128 return m_valueChanged || prevValueChanged;
131 void VarTree::inferTypesOfChildren(ProgramTypeTable& typeTable)
134 * Type inference works like this: We use type information of those
135 * children that have a type name in their name (base classes) or in
136 * their value (pointers)
139 // first recurse children
140 VarTree* child = static_cast<VarTree*>(getChild());
141 while (child != 0) {
142 child->inferTypesOfChildren(typeTable);
143 child = static_cast<VarTree*>(child->getSibling());
146 // if this is a pointer, get the type from the value (less the pointer)
147 if (m_varKind == VKpointer) {
148 #ifndef I_know_a_way_to_do_this_cleanly
149 return;
150 #else
151 const char* p = m_value.data();
152 const char* start = p;
153 // the type of the pointer shows up in the value (sometimes)
154 if (p == 0 || *p != '(')
155 return;
156 skipNested(p, '(', ')');
158 * We only recognize pointers to data "(int *)" but not pointers
159 * to functions "(void (*)())".
161 if (p-start < 3 && /* at least 3 chars necessary: (*) */
162 p[-2] != '*') /* skip back before the closing paren */
164 return;
166 const QString& typeName =
167 FROM_LATIN1(start+1, p-start-3) // minus 3 chars
168 .stripWhiteSpace();
169 m_type = typeTable.lookup(typeName);
170 if (m_type == 0) {
171 m_type = TypeInfo::unknownType();
173 #endif
174 } else if (m_varKind == VKstruct) {
175 // check if this is a base class part
176 if (m_nameKind == NKtype) {
177 const QString& typeName =
178 text.mid(1, text.length()-2); // strip < and >
179 m_type = typeTable.lookup(typeName);
181 /* if we don't have a type yet, get it from the base class */
182 if (m_type == 0) {
183 m_type = inferTypeFromBaseClass();
185 * If there is a known type now, it is the one from the
186 * first base class whose type we know.
191 * If we still don't have a type, the type is really unknown.
193 if (m_type == 0) {
194 m_type = TypeInfo::unknownType();
196 } // else
198 * This is not a base class part. We don't assign a type so
199 * that later we can ask gdb.
205 * Get the type of the first base class whose type we know.
207 TypeInfo* VarTree::inferTypeFromBaseClass()
209 if (m_varKind == VKstruct) {
210 VarTree* child = static_cast<VarTree*>(getChild());
211 while (child != 0 &&
212 // only check base class parts (i.e. type names)
213 child->m_nameKind == NKtype)
215 if (child->m_type != 0 &&
216 child->m_type != TypeInfo::unknownType())
218 // got a type!
219 return child->m_type;
221 child = static_cast<VarTree*>(child->getSibling());
224 return 0;
228 ExprWnd::ExprWnd(QWidget* parent, const char* name) :
229 KTreeView(parent, name),
230 maxValueWidth(0)
232 setNumCols(2);
233 clearTableFlags(Tbl_clipCellPainting);
235 connect(this, SIGNAL(expanded(int)), SLOT(slotExpandOrCollapse(int)));
236 connect(this, SIGNAL(collapsed(int)), SLOT(slotExpandOrCollapse(int)));
238 #if QT_VERSION < 200
239 KIconLoader* loader = kapp->getIconLoader();
240 m_pixPointer = loader->loadIcon("pointer.xpm");
241 #else
242 m_pixPointer = BarIcon("pointer.xpm");
243 #endif
244 if (m_pixPointer.isNull())
245 TRACE("Can't load pointer.xpm");
248 ExprWnd::~ExprWnd()
252 void ExprWnd::exprList(QStrList& exprs)
254 // ASSERT(exprs does deep-copies)
255 KTreeViewItem* item;
256 for (item = itemAt(0); item != 0; item = item->getSibling()) {
257 exprs.append(item->getText());
261 void ExprWnd::insertExpr(VarTree* expr)
263 // append the expression
264 insertItem(expr);
266 collectUnknownTypes(expr);
268 updateValuesWidth();
271 void ExprWnd::updateExpr(VarTree* expr)
273 // search the root variable
274 QString p = expr->getText();
275 KPath path;
276 path.push(&p);
277 KTreeViewItem* item = itemAt(path);
278 path.pop();
279 if (item == 0) {
280 return;
282 // now update it
283 if (updateExprRec(static_cast<VarTree*>(item), expr)) {
284 updateVisibleItems();
285 updateValuesWidth();
286 repaint();
288 collectUnknownTypes(static_cast<VarTree*>(item));
291 void ExprWnd::updateExpr(VarTree* display, VarTree* newValues)
293 if (updateExprRec(display, newValues) && display->isVisible()) {
294 updateVisibleItems();
295 updateValuesWidth();
296 repaint();
298 collectUnknownTypes(display);
302 * returns true if there's a visible change
304 bool ExprWnd::updateExprRec(VarTree* display, VarTree* newValues)
306 bool isExpanded = display->isExpanded();
309 * If we are updating a pointer without children by a dummy, we don't
310 * collapse it, but simply insert the new children. This happens when a
311 * pointer has just been expanded by the user.
313 if (display->m_varKind == VarTree::VKpointer &&
314 display->childCount() == 0 &&
315 newValues->m_varKind == VarTree::VKdummy)
317 replaceChildren(display, newValues);
318 return isExpanded; /* no visible change if not expanded */
322 * If the display and newValues have different kind or if their number
323 * of children is different, replace the whole sub-tree.
325 if (// the next two lines mean: not(m_varKind remains unchanged)
326 !(newValues->m_varKind == VarTree::VKdummy ||
327 display->m_varKind == newValues->m_varKind)
329 (display->childCount() != newValues->childCount() &&
331 * If this is a pointer and newValues doesn't have children, we
332 * don't replace the sub-tree; instead, below we mark this
333 * sub-tree for requiring an update.
335 (display->m_varKind != VarTree::VKpointer ||
336 newValues->childCount() != 0)))
338 if (isExpanded) {
339 collapseSubTree(display, false);
342 // since children changed, it is likely that the type has also changed
343 display->m_type = 0; /* will re-evaluate the type */
345 // display the new value
346 updateSingleExpr(display, newValues);
347 replaceChildren(display, newValues);
349 // update the m_varKind
350 if (newValues->m_varKind != VarTree::VKdummy) {
351 display->m_varKind = newValues->m_varKind;
352 display->setDelayedExpanding(newValues->m_varKind == VarTree::VKpointer);
355 // (note that the new value might not have a sub-tree at all)
356 return display->m_valueChanged || isExpanded; /* no visible change if not expanded */
359 // display the new value
360 updateSingleExpr(display, newValues);
363 * If this is an expanded pointer, record it for being updated.
365 if (display->m_varKind == VarTree::VKpointer) {
366 if (isExpanded &&
367 // if newValues is a dummy, we have already updated this pointer
368 newValues->m_varKind != VarTree::VKdummy)
370 m_updatePtrs.append(display);
373 * If the visible sub-tree has children, but newValues doesn't, we
374 * can stop here.
376 if (newValues->childCount() == 0) {
377 return display->m_valueChanged;
381 ASSERT(display->childCount() == newValues->childCount());
383 // go for children
384 bool childChanged = false;
386 VarTree* vDisplay = static_cast<VarTree*>(display->getChild());
387 VarTree* vNew = static_cast<VarTree*>(newValues->getChild());
388 while (vDisplay != 0) {
389 // check whether the names are the same
390 if (strcmp(vDisplay->getText(), vNew->getText()) != 0) {
391 // set new name
392 vDisplay->setText(vNew->getText());
393 int i = itemRow(vDisplay);
394 if (i >= 0) {
395 updateCell(i, 0, true);
396 childChanged = true;
399 // recurse
400 if (updateExprRec(vDisplay, vNew)) {
401 childChanged = true;
403 vDisplay = static_cast<VarTree*>(vDisplay->getSibling());
404 vNew = static_cast<VarTree*>(vNew->getSibling());
407 // update of children propagates only if this node is expanded
408 return display->m_valueChanged || (display->isExpanded() && childChanged);
411 void ExprWnd::updateSingleExpr(VarTree* display, VarTree* newValue)
414 * If newValues is a VKdummy, we are only interested in its children.
415 * No need to update anything here.
417 if (newValue->m_varKind == VarTree::VKdummy) {
418 return;
422 * If this node is a struct and we know its type then don't update its
423 * value now. This is a node for which we know how to find a nested
424 * value. So register the node for an update.
426 if (display->m_varKind == VarTree::VKstruct &&
427 display->m_type != 0 &&
428 display->m_type != TypeInfo::unknownType())
430 ASSERT(newValue->m_varKind == VarTree::VKstruct);
431 display->m_partialValue = display->m_type->m_displayString[0];
432 m_updateStruct.append(display);
434 else
436 if (display->updateValue(newValue->m_value)) {
437 int i = itemRow(display);
438 if (i >= 0) {
439 updateCell(i, 1, true);
445 void ExprWnd::updateStructValue(VarTree* display)
447 ASSERT(display->m_varKind == VarTree::VKstruct);
449 if (display->updateValue(display->m_partialValue)) {
450 int i = itemRow(display);
451 if (i >= 0) {
452 updateCell(i, 1, true);
453 updateValuesWidth();
456 // reset the value
457 display->m_partialValue = "";
458 display->m_exprIndex = -1;
461 void ExprWnd::replaceChildren(VarTree* display, VarTree* newValues)
463 ASSERT(display->childCount() == 0 || display->m_varKind != VarTree::VKsimple);
465 // delete all children of display
466 KTreeViewItem* c;
467 while ((c = display->getChild()) != 0) {
468 display->removeChild(c);
470 // insert copies of the newValues
471 for (c = newValues->getChild(); c != 0; c = c->getSibling()) {
472 VarTree* v = static_cast<VarTree*>(c);
473 VarTree* vNew = new VarTree(v->getText(), v->m_nameKind);
474 vNew->m_varKind = v->m_varKind;
475 vNew->m_value = v->m_value;
476 vNew->m_type = v->m_type;
477 vNew->setDelayedExpanding(vNew->m_varKind == VarTree::VKpointer);
478 display->appendChild(vNew);
479 // recurse
480 replaceChildren(vNew, v);
484 void ExprWnd::collectUnknownTypes(VarTree* var)
487 * forEveryItem does not scan the root item itself. So we must do it
488 * ourselves.
490 ASSERT(var->m_varKind != VarTree::VKpointer || var->m_nameKind != VarTree::NKtype);
491 if (var->m_type == 0 &&
492 var->m_varKind == VarTree::VKstruct &&
493 var->m_nameKind != VarTree::NKtype)
495 /* this struct node doesn't have a type yet: register it */
496 m_updateType.append(var);
499 // add pointer pixmap to pointers
500 if (var->m_varKind == VarTree::VKpointer) {
501 var->setPixmap(m_pixPointer);
504 forEveryItem(collectUnknownTypes, this, var);
507 bool ExprWnd::collectUnknownTypes(KTreeViewItem* item, void* user)
509 VarTree* var = static_cast<VarTree*>(item);
510 ExprWnd* tree = static_cast<ExprWnd*>(user);
511 ASSERT(var->m_varKind != VarTree::VKpointer || var->m_nameKind != VarTree::NKtype);
512 if (var->m_type == 0 &&
513 var->m_varKind == VarTree::VKstruct &&
514 var->m_nameKind != VarTree::NKtype)
516 /* this struct node doesn't have a type yet: register it */
517 tree->m_updateType.append(var);
519 // add pointer pixmap to pointers
520 if (var->m_varKind == VarTree::VKpointer) {
521 var->setPixmap(tree->m_pixPointer);
523 return false;
527 VarTree* ExprWnd::topLevelExprByName(const char* name)
529 QString p = name;
530 KPath path;
531 path.push(&p);
532 KTreeViewItem* item = itemAt(path);
533 path.pop();
535 return static_cast<VarTree*>(item);
538 void ExprWnd::removeExpr(VarTree* item)
540 // must remove any pointers scheduled for update from the list
541 sweepList(m_updatePtrs, item);
542 sweepList(m_updateType, item);
543 sweepList(m_updateStruct, item);
545 takeItem(item);
546 delete item;
548 updateValuesWidth();
551 void ExprWnd::sweepList(QList<VarTree>& list, VarTree* subTree)
553 if (subTree == 0)
554 return;
556 VarTree* checkItem = list.first();
557 while (checkItem != 0) {
558 if (!subTree->isAncestorEq(checkItem)) {
559 // checkItem is not an item from subTree
560 // advance
561 checkItem = list.next();
562 } else {
563 // checkItem is an item from subTree
565 * If checkItem is the last item in the list, we need a special
566 * treatment, because remove()ing it steps the current item of
567 * the list in the "wrong" direction.
569 if (checkItem == list.getLast()) { // does not set current item
570 list.remove();
571 /* we deleted the last element, so we've finished */
572 checkItem = 0;
573 } else {
574 list.remove();
575 /* remove() advanced already */
576 checkItem = list.current();
582 QString ExprWnd::exprStringAt(int index)
584 KTreeViewItem* item = itemAt(index);
585 if (item == 0) return QString(); /* paranoia */
586 VarTree* expr = static_cast<VarTree*>(item);
587 return expr->computeExpr();
590 void ExprWnd::clearPendingUpdates()
592 m_updatePtrs.clear();
593 m_updateType.clear();
594 m_updateStruct.clear();
597 VarTree* ExprWnd::nextUpdatePtr()
599 VarTree* ptr = m_updatePtrs.first();
600 if (ptr != 0) {
601 m_updatePtrs.remove();
603 return ptr;
606 VarTree* ExprWnd::nextUpdateType()
608 VarTree* ptr = m_updateType.first();
609 if (ptr != 0) {
610 m_updateType.remove();
612 return ptr;
615 VarTree* ExprWnd::nextUpdateStruct()
617 VarTree* ptr = m_updateStruct.first();
618 if (ptr != 0) {
619 m_updateStruct.remove();
621 return ptr;
624 void ExprWnd::paintCell(QPainter* painter, int row, int col)
626 if (col == 0) {
627 KTreeView::paintCell(painter, row, col);
628 } else {
629 VarTree* item = static_cast<VarTree*>(itemAt(row));
630 if (item != 0) {
631 item->paintValue(painter);
636 int ExprWnd::cellWidth(int col)
638 if (col == 0) {
639 return KTreeView::cellWidth(col);
640 } else {
641 return maxValueWidth;
645 void ExprWnd::updateValuesWidth()
647 int maxW = 0;
648 forEveryVisibleItem(static_cast<KForEveryFunc>(&getMaxValueWidth), &maxW);
649 maxValueWidth = maxW;
650 updateTableSize();
653 // called by updateValuesWidth() for each item in the visible list
654 bool ExprWnd::getMaxValueWidth(KTreeViewItem* item, void* user)
656 int *maxW = (int *)user;
657 VarTree* v = static_cast<VarTree*>(item);
658 int w = v->valueWidth();
659 if(w > *maxW)
660 *maxW = w;
661 return false;
664 void ExprWnd::slotExpandOrCollapse(int)
666 updateValuesWidth();