3 // Copyright by Johannes Sixt
4 // This file is under GPL, the GNU General Public Licence
12 #include <kiconloader.h> /* icons */
18 VarTree::VarTree(const QString
& name
, NameKind aKind
) :
22 m_valueChanged(false),
25 m_exprIndexUseGuard(false)
33 void VarTree::paintValue(QPainter
* p
)
36 int cellHeight
= height(p
->fontMetrics());
38 int textY
= (cellHeight
- p
->fontMetrics().height()) / 2 +
39 p
->fontMetrics().ascent();
44 // p->setBackgroundColor(cg.base());
45 p
->drawText(textX
, textY
, m_value
, m_value
.length());
49 int VarTree::valueWidth()
52 return owner
->fontMetrics().width(m_value
) + 4;
55 QString
VarTree::computeExpr() const
57 assert(getParent() != 0);
62 // top-level items are special
63 if (getParent()->getParent() == 0)
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
) {
74 /* augment by this item's text */
76 /* if this is an address, dereference it */
77 if (m_nameKind
== NKaddress
) {
78 ASSERT(par
->m_varKind
== VKpointer
);
79 result
= "*" + parentExpr
;
82 switch (par
->m_varKind
) {
84 result
= "(" + parentExpr
+ ")" + getText();
87 result
= "(" + parentExpr
+ ")." + getText();
89 case VKsimple
: /* parent can't be simple */
90 case VKpointer
: /* handled in NKaddress */
91 case VKdummy
: /* can't occur at all */
93 result
= parentExpr
; /* paranoia */
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) {
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
) {
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
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());
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
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
!= '(')
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 */
166 const QString
& typeName
=
167 FROM_LATIN1(start
+1, p
-start
-3) // minus 3 chars
169 m_type
= typeTable
.lookup(typeName
);
171 m_type
= TypeInfo::unknownType();
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 */
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.
194 m_type
= TypeInfo::unknownType();
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());
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())
219 return child
->m_type
;
221 child
= static_cast<VarTree
*>(child
->getSibling());
228 ExprWnd::ExprWnd(QWidget
* parent
, const char* name
) :
229 KTreeView(parent
, name
),
233 clearTableFlags(Tbl_clipCellPainting
);
235 connect(this, SIGNAL(expanded(int)), SLOT(slotExpandOrCollapse(int)));
236 connect(this, SIGNAL(collapsed(int)), SLOT(slotExpandOrCollapse(int)));
239 KIconLoader
* loader
= kapp
->getIconLoader();
240 m_pixPointer
= loader
->loadIcon("pointer.xpm");
242 m_pixPointer
= BarIcon("pointer.xpm");
244 if (m_pixPointer
.isNull())
245 TRACE("Can't load pointer.xpm");
252 void ExprWnd::exprList(QStrList
& exprs
)
254 // ASSERT(exprs does deep-copies)
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
266 collectUnknownTypes(expr
);
271 void ExprWnd::updateExpr(VarTree
* expr
)
273 // search the root variable
274 QString p
= expr
->getText();
277 KTreeViewItem
* item
= itemAt(path
);
283 if (updateExprRec(static_cast<VarTree
*>(item
), expr
)) {
284 updateVisibleItems();
288 collectUnknownTypes(static_cast<VarTree
*>(item
));
291 void ExprWnd::updateExpr(VarTree
* display
, VarTree
* newValues
)
293 if (updateExprRec(display
, newValues
) && display
->isVisible()) {
294 updateVisibleItems();
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)))
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
) {
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
376 if (newValues
->childCount() == 0) {
377 return display
->m_valueChanged
;
381 ASSERT(display
->childCount() == newValues
->childCount());
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) {
392 vDisplay
->setText(vNew
->getText());
393 int i
= itemRow(vDisplay
);
395 updateCell(i
, 0, true);
400 if (updateExprRec(vDisplay
, vNew
)) {
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
) {
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
);
436 if (display
->updateValue(newValue
->m_value
)) {
437 int i
= itemRow(display
);
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
);
452 updateCell(i
, 1, true);
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
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
);
480 replaceChildren(vNew
, v
);
484 void ExprWnd::collectUnknownTypes(VarTree
* var
)
487 * forEveryItem does not scan the root item itself. So we must do it
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
);
527 VarTree
* ExprWnd::topLevelExprByName(const char* name
)
532 KTreeViewItem
* item
= itemAt(path
);
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
);
551 void ExprWnd::sweepList(QList
<VarTree
>& list
, VarTree
* subTree
)
556 VarTree
* checkItem
= list
.first();
557 while (checkItem
!= 0) {
558 if (!subTree
->isAncestorEq(checkItem
)) {
559 // checkItem is not an item from subTree
561 checkItem
= list
.next();
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
571 /* we deleted the last element, so we've finished */
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();
601 m_updatePtrs
.remove();
606 VarTree
* ExprWnd::nextUpdateType()
608 VarTree
* ptr
= m_updateType
.first();
610 m_updateType
.remove();
615 VarTree
* ExprWnd::nextUpdateStruct()
617 VarTree
* ptr
= m_updateStruct
.first();
619 m_updateStruct
.remove();
624 void ExprWnd::paintCell(QPainter
* painter
, int row
, int col
)
627 KTreeView::paintCell(painter
, row
, col
);
629 VarTree
* item
= static_cast<VarTree
*>(itemAt(row
));
631 item
->paintValue(painter
);
636 int ExprWnd::cellWidth(int col
)
639 return KTreeView::cellWidth(col
);
641 return maxValueWidth
;
645 void ExprWnd::updateValuesWidth()
648 forEveryVisibleItem(static_cast<KForEveryFunc
>(&getMaxValueWidth
), &maxW
);
649 maxValueWidth
= maxW
;
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();
664 void ExprWnd::slotExpandOrCollapse(int)