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
) {
85 QString index
= getText();
87 // skip past the index
88 while (index
[i
].isDigit())
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
;
102 result
= "(" + parentExpr
+ ")." + getText();
104 case VKsimple
: /* parent can't be simple */
105 case VKpointer
: /* handled in NKaddress */
106 case VKdummy
: /* can't occur at all */
108 result
= parentExpr
; /* paranoia */
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) {
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
) {
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
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());
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
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
!= '(')
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 */
181 const QString
& typeName
=
182 FROM_LATIN1(start
+1, p
-start
-3) // minus 3 chars
184 m_type
= typeTable
.lookup(typeName
);
186 m_type
= TypeInfo::unknownType();
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 */
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.
209 m_type
= TypeInfo::unknownType();
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());
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())
234 return child
->m_type
;
236 child
= static_cast<VarTree
*>(child
->getSibling());
243 ExprWnd::ExprWnd(QWidget
* parent
, const char* name
) :
244 KTreeView(parent
, name
),
249 connect(this, SIGNAL(expanded(int)), SLOT(slotExpandOrCollapse(int)));
250 connect(this, SIGNAL(collapsed(int)), SLOT(slotExpandOrCollapse(int)));
253 KIconLoader
* loader
= kapp
->getIconLoader();
254 m_pixPointer
= loader
->loadIcon("pointer.xpm");
256 m_pixPointer
= BarIcon("pointer.xpm");
258 if (m_pixPointer
.isNull())
259 TRACE("Can't load pointer.xpm");
266 void ExprWnd::exprList(QStrList
& exprs
)
268 // ASSERT(exprs does deep-copies)
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
280 collectUnknownTypes(expr
);
285 void ExprWnd::updateExpr(VarTree
* expr
)
287 // search the root variable
288 QString p
= expr
->getText();
291 KTreeViewItem
* item
= itemAt(path
);
297 if (updateExprRec(static_cast<VarTree
*>(item
), expr
)) {
298 updateVisibleItems();
302 collectUnknownTypes(static_cast<VarTree
*>(item
));
305 void ExprWnd::updateExpr(VarTree
* display
, VarTree
* newValues
)
307 if (updateExprRec(display
, newValues
) && display
->isVisible()) {
308 updateVisibleItems();
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)))
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
) {
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
390 if (newValues
->childCount() == 0) {
391 return display
->m_valueChanged
;
395 ASSERT(display
->childCount() == newValues
->childCount());
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) {
406 vDisplay
->setText(vNew
->getText());
407 int i
= itemRow(vDisplay
);
409 updateCell(i
, 0, true);
414 if (updateExprRec(vDisplay
, vNew
)) {
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
) {
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
);
450 if (display
->updateValue(newValue
->m_value
)) {
451 int i
= itemRow(display
);
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
);
467 updateCell(i
, 1, true);
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
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
);
494 replaceChildren(vNew
, v
);
498 void ExprWnd::collectUnknownTypes(VarTree
* var
)
501 * forEveryItem does not scan the root item itself. So we must do it
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
);
541 VarTree
* ExprWnd::topLevelExprByName(const char* name
)
546 KTreeViewItem
* item
= itemAt(path
);
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
);
565 void ExprWnd::sweepList(QList
<VarTree
>& list
, VarTree
* subTree
)
570 VarTree
* checkItem
= list
.first();
571 while (checkItem
!= 0) {
572 if (!subTree
->isAncestorEq(checkItem
)) {
573 // checkItem is not an item from subTree
575 checkItem
= list
.next();
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
585 /* we deleted the last element, so we've finished */
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();
615 m_updatePtrs
.remove();
620 VarTree
* ExprWnd::nextUpdateType()
622 VarTree
* ptr
= m_updateType
.first();
624 m_updateType
.remove();
629 VarTree
* ExprWnd::nextUpdateStruct()
631 VarTree
* ptr
= m_updateStruct
.first();
633 m_updateStruct
.remove();
638 void ExprWnd::paintCell(QPainter
* painter
, int row
, int col
)
641 KTreeView::paintCell(painter
, row
, col
);
643 VarTree
* item
= static_cast<VarTree
*>(itemAt(row
));
645 item
->paintValue(painter
);
650 int ExprWnd::cellWidth(int col
) const
653 return KTreeView::cellWidth(col
);
655 return maxValueWidth
;
659 void ExprWnd::updateValuesWidth()
662 forEveryVisibleItem(static_cast<KForEveryFunc
>(&getMaxValueWidth
), &maxW
);
663 maxValueWidth
= maxW
;
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();
678 void ExprWnd::slotExpandOrCollapse(int)