3 // Copyright by Johannes Sixt
4 // This file is under GPL, the GNU General Public Licence
11 #include <qscrollbar.h>
13 #include <kiconloader.h> /* icons */
19 VarTree::VarTree(const QString
& name
, NameKind aKind
) :
23 m_valueChanged(false),
26 m_exprIndexUseGuard(false)
34 void VarTree::paintValue(QPainter
* p
)
37 int cellHeight
= height(p
->fontMetrics());
39 int textY
= (cellHeight
- p
->fontMetrics().height()) / 2 +
40 p
->fontMetrics().ascent();
45 // p->setBackgroundColor(cg.base());
46 p
->drawText(textX
, textY
, m_value
, m_value
.length());
50 int VarTree::valueWidth()
53 return owner
->fontMetrics().width(m_value
) + 4;
56 QString
VarTree::computeExpr() const
58 assert(getParent() != 0);
63 // top-level items are special
64 if (getParent()->getParent() == 0)
68 VarTree
* par
= static_cast<VarTree
*>(getParent());
69 QString parentExpr
= par
->computeExpr();
71 /* don't add this item's name if this is a base class sub-item */
72 if (m_nameKind
== NKtype
) {
75 /* augment by this item's text */
77 /* if this is an address, dereference it */
78 if (m_nameKind
== NKaddress
) {
79 ASSERT(par
->m_varKind
== VKpointer
);
80 result
= "*" + parentExpr
;
83 switch (par
->m_varKind
) {
86 QString index
= getText();
88 // skip past the index
89 while (index
[i
].isDigit())
92 * Some array indices are actually ranges due to repeated array
93 * values. We use the first index in these cases.
95 if (index
[i
] != ']') {
96 // remove second index
97 index
.remove(i
, index
.length()-i
-1);
99 result
= "(" + parentExpr
+ ")" + index
;
103 result
= "(" + parentExpr
+ ")." + getText();
105 case VKsimple
: /* parent can't be simple */
106 case VKpointer
: /* handled in NKaddress */
107 case VKdummy
: /* can't occur at all */
109 result
= parentExpr
; /* paranoia */
115 bool VarTree::isToplevelExpr() const
117 return getParent() != 0 && getParent()->getParent() == 0;
120 bool VarTree::isAncestorEq(const VarTree
* child
) const
122 const KTreeViewItem
* c
= child
;
123 while (c
!= 0 && c
!= this) {
129 bool VarTree::updateValue(const QString
& newValue
)
131 // check whether the value changed
132 bool prevValueChanged
= m_valueChanged
;
133 m_valueChanged
= false;
134 if (m_value
!= newValue
) {
136 m_valueChanged
= true;
139 * We must repaint the cell if the value changed. If it did not change,
140 * we still must repaint the cell if the value changed previously,
141 * because the color of the display must be changed (from red to
144 return m_valueChanged
|| prevValueChanged
;
147 void VarTree::inferTypesOfChildren(ProgramTypeTable
& typeTable
)
150 * Type inference works like this: We use type information of those
151 * children that have a type name in their name (base classes) or in
152 * their value (pointers)
155 // first recurse children
156 VarTree
* child
= static_cast<VarTree
*>(getChild());
158 child
->inferTypesOfChildren(typeTable
);
159 child
= static_cast<VarTree
*>(child
->getSibling());
162 // if this is a pointer, get the type from the value (less the pointer)
163 if (m_varKind
== VKpointer
) {
167 * wchart_t pointers must be treated as struct, because the array
168 * of characters is printed similar to how QStrings are decoded.
170 m_varKind
= VKstruct
;
171 setDelayedExpanding(false);
174 #ifndef I_know_a_way_to_do_this_cleanly
177 const char* p
= m_value
.data();
178 const char* start
= p
;
179 // the type of the pointer shows up in the value (sometimes)
180 if (p
== 0 || *p
!= '(')
182 skipNested(p
, '(', ')');
184 * We only recognize pointers to data "(int *)" but not pointers
185 * to functions "(void (*)())".
187 if (p
-start
< 3 && /* at least 3 chars necessary: (*) */
188 p
[-2] != '*') /* skip back before the closing paren */
192 const QString
& typeName
=
193 QString::fromLatin1(start
+1, p
-start
-3) // minus 3 chars
195 m_type
= typeTable
.lookup(typeName
);
197 m_type
= TypeInfo::unknownType();
200 } else if (m_varKind
== VKstruct
) {
201 // check if this is a base class part
202 if (m_nameKind
== NKtype
) {
203 const QString
& typeName
=
204 text
.mid(1, text
.length()-2); // strip < and >
205 m_type
= typeTable
.lookup(typeName
);
207 /* if we don't have a type yet, get it from the base class */
209 m_type
= inferTypeFromBaseClass();
211 * If there is a known type now, it is the one from the
212 * first base class whose type we know.
217 * If we still don't have a type, the type is really unknown.
220 m_type
= TypeInfo::unknownType();
224 * This is not a base class part. We don't assign a type so
225 * that later we can ask gdb.
230 // the value contains the pointer type in parenthesis
231 bool VarTree::isWcharT() const
233 return m_value
.startsWith("(const wchar_t *)") ||
234 m_value
.startsWith("(wchar_t *)");
238 * Get the type of the first base class whose type we know.
240 TypeInfo
* VarTree::inferTypeFromBaseClass()
242 if (m_varKind
== VKstruct
) {
243 VarTree
* child
= static_cast<VarTree
*>(getChild());
245 // only check base class parts (i.e. type names)
246 child
->m_nameKind
== NKtype
)
248 if (child
->m_type
!= 0 &&
249 child
->m_type
!= TypeInfo::unknownType())
252 return child
->m_type
;
254 child
= static_cast<VarTree
*>(child
->getSibling());
261 ExprWnd::ExprWnd(QWidget
* parent
, const char* name
) :
262 KTreeView(parent
, name
),
268 connect(this, SIGNAL(expanded(int)), SLOT(slotExpandOrCollapse(int)));
269 connect(this, SIGNAL(collapsed(int)), SLOT(slotExpandOrCollapse(int)));
271 m_pixPointer
= UserIcon("pointer.xpm");
272 if (m_pixPointer
.isNull())
273 TRACE("Can't load pointer.xpm");
280 void ExprWnd::exprList(QStrList
& exprs
)
282 // ASSERT(exprs does deep-copies)
284 for (item
= itemAt(0); item
!= 0; item
= item
->getSibling()) {
285 exprs
.append(item
->getText());
289 void ExprWnd::insertExpr(VarTree
* expr
)
291 // append the expression
294 collectUnknownTypes(expr
);
299 void ExprWnd::updateExpr(VarTree
* expr
)
301 // search the root variable
303 path
.push(expr
->getText());
304 KTreeViewItem
* item
= itemAt(path
);
309 if (updateExprRec(static_cast<VarTree
*>(item
), expr
)) {
310 updateVisibleItems();
314 collectUnknownTypes(static_cast<VarTree
*>(item
));
317 void ExprWnd::updateExpr(VarTree
* display
, VarTree
* newValues
)
319 if (updateExprRec(display
, newValues
) && display
->isVisible()) {
320 updateVisibleItems();
324 collectUnknownTypes(display
);
328 * returns true if there's a visible change
330 bool ExprWnd::updateExprRec(VarTree
* display
, VarTree
* newValues
)
332 bool isExpanded
= display
->isExpanded();
335 * If we are updating a pointer without children by a dummy, we don't
336 * collapse it, but simply insert the new children. This happens when a
337 * pointer has just been expanded by the user.
339 if (display
->m_varKind
== VarTree::VKpointer
&&
340 display
->childCount() == 0 &&
341 newValues
->m_varKind
== VarTree::VKdummy
)
343 replaceChildren(display
, newValues
);
344 return isExpanded
; /* no visible change if not expanded */
348 * If the display and newValues have different kind or if their number
349 * of children is different, replace the whole sub-tree.
351 if (// the next two lines mean: not(m_varKind remains unchanged)
352 !(newValues
->m_varKind
== VarTree::VKdummy
||
353 display
->m_varKind
== newValues
->m_varKind
)
355 (display
->childCount() != newValues
->childCount() &&
357 * If this is a pointer and newValues doesn't have children, we
358 * don't replace the sub-tree; instead, below we mark this
359 * sub-tree for requiring an update.
361 (display
->m_varKind
!= VarTree::VKpointer
||
362 newValues
->childCount() != 0)))
365 collapseSubTree(display
, false);
368 // since children changed, it is likely that the type has also changed
369 display
->m_type
= 0; /* will re-evaluate the type */
371 // display the new value
372 updateSingleExpr(display
, newValues
);
373 replaceChildren(display
, newValues
);
375 // update the m_varKind
376 if (newValues
->m_varKind
!= VarTree::VKdummy
) {
377 display
->m_varKind
= newValues
->m_varKind
;
378 display
->setDelayedExpanding(newValues
->m_varKind
== VarTree::VKpointer
);
381 // (note that the new value might not have a sub-tree at all)
382 return display
->m_valueChanged
|| isExpanded
; /* no visible change if not expanded */
385 // display the new value
386 updateSingleExpr(display
, newValues
);
389 * If this is an expanded pointer, record it for being updated.
391 if (display
->m_varKind
== VarTree::VKpointer
) {
393 // if newValues is a dummy, we have already updated this pointer
394 newValues
->m_varKind
!= VarTree::VKdummy
)
396 m_updatePtrs
.append(display
);
399 * If the visible sub-tree has children, but newValues doesn't, we
402 if (newValues
->childCount() == 0) {
403 return display
->m_valueChanged
;
407 ASSERT(display
->childCount() == newValues
->childCount());
410 bool childChanged
= false;
412 VarTree
* vDisplay
= static_cast<VarTree
*>(display
->getChild());
413 VarTree
* vNew
= static_cast<VarTree
*>(newValues
->getChild());
414 while (vDisplay
!= 0) {
415 // check whether the names are the same
416 if (strcmp(vDisplay
->getText(), vNew
->getText()) != 0) {
418 vDisplay
->setText(vNew
->getText());
419 int i
= itemRow(vDisplay
);
421 updateCell(i
, 0, true);
426 if (updateExprRec(vDisplay
, vNew
)) {
429 vDisplay
= static_cast<VarTree
*>(vDisplay
->getSibling());
430 vNew
= static_cast<VarTree
*>(vNew
->getSibling());
433 // update of children propagates only if this node is expanded
434 return display
->m_valueChanged
|| (display
->isExpanded() && childChanged
);
437 void ExprWnd::updateSingleExpr(VarTree
* display
, VarTree
* newValue
)
440 * If newValues is a VKdummy, we are only interested in its children.
441 * No need to update anything here.
443 if (newValue
->m_varKind
== VarTree::VKdummy
) {
448 * If this node is a struct and we know its type then don't update its
449 * value now. This is a node for which we know how to find a nested
450 * value. So register the node for an update.
452 * wchar_t types are also treated specially here: We consider them
453 * as struct (has been set in inferTypesOfChildren()).
455 if (display
->m_varKind
== VarTree::VKstruct
&&
456 display
->m_type
!= 0 &&
457 display
->m_type
!= TypeInfo::unknownType())
459 ASSERT(newValue
->m_varKind
== VarTree::VKstruct
);
460 if (display
->m_type
== TypeInfo::wchartType())
463 * We do not copy the new pointer value to the destination right
464 * away, but consider it as the first part of the nested value.
465 * Then the display will change its color only when the new value
468 display
->m_partialValue
= formatWCharPointer(newValue
->m_value
);
471 display
->m_partialValue
= display
->m_type
->m_displayString
[0];
472 m_updateStruct
.append(display
);
476 if (display
->updateValue(newValue
->m_value
)) {
477 int i
= itemRow(display
);
479 updateCell(i
, 1, true);
485 void ExprWnd::updateStructValue(VarTree
* display
)
487 ASSERT(display
->m_varKind
== VarTree::VKstruct
);
489 if (display
->updateValue(display
->m_partialValue
)) {
490 int i
= itemRow(display
);
493 updateCell(i
, 1, true);
497 display
->m_partialValue
= "";
498 display
->m_exprIndex
= -1;
501 void ExprWnd::replaceChildren(VarTree
* display
, VarTree
* newValues
)
503 ASSERT(display
->childCount() == 0 || display
->m_varKind
!= VarTree::VKsimple
);
505 // delete all children of display
506 while (VarTree
* c
= static_cast<VarTree
*>(display
->getChild())) {
508 display
->removeChild(c
);
511 // insert copies of the newValues
512 for (KTreeViewItem
* c
= newValues
->getChild(); c
!= 0; c
= c
->getSibling()) {
513 VarTree
* v
= static_cast<VarTree
*>(c
);
514 VarTree
* vNew
= new VarTree(v
->getText(), v
->m_nameKind
);
515 vNew
->m_varKind
= v
->m_varKind
;
516 vNew
->m_value
= v
->m_value
;
517 vNew
->m_type
= v
->m_type
;
518 vNew
->setDelayedExpanding(vNew
->m_varKind
== VarTree::VKpointer
);
519 vNew
->setExpanded(v
->isExpanded());
520 display
->appendChild(vNew
);
522 replaceChildren(vNew
, v
);
526 void ExprWnd::collectUnknownTypes(VarTree
* var
)
529 * forEveryItem does not scan the root item itself. So we must do it
532 ASSERT(var
->m_varKind
!= VarTree::VKpointer
|| var
->m_nameKind
!= VarTree::NKtype
);
533 if (var
->m_type
== 0 &&
534 var
->m_varKind
== VarTree::VKstruct
&&
535 var
->m_nameKind
!= VarTree::NKtype
)
537 if (!var
->isWcharT())
539 /* this struct node doesn't have a type yet: register it */
540 m_updateType
.append(var
);
544 var
->m_type
= TypeInfo::wchartType();
545 // see updateSingleExpr() why we move the value
546 var
->m_partialValue
= formatWCharPointer(var
->m_value
);
547 var
->m_value
.truncate(0);
548 m_updateStruct
.append(var
);
552 // add pointer pixmap to pointers
553 if (var
->m_varKind
== VarTree::VKpointer
) {
554 var
->setPixmap(m_pixPointer
);
557 forEveryItem(collectUnknownTypes
, this, var
);
560 bool ExprWnd::collectUnknownTypes(KTreeViewItem
* item
, void* user
)
562 VarTree
* var
= static_cast<VarTree
*>(item
);
563 ExprWnd
* tree
= static_cast<ExprWnd
*>(user
);
564 ASSERT(var
->m_varKind
!= VarTree::VKpointer
|| var
->m_nameKind
!= VarTree::NKtype
);
565 if (var
->m_type
== 0 &&
566 var
->m_varKind
== VarTree::VKstruct
&&
567 var
->m_nameKind
!= VarTree::NKtype
)
569 if (!var
->isWcharT())
571 /* this struct node doesn't have a type yet: register it */
572 tree
->m_updateType
.append(var
);
576 var
->m_type
= TypeInfo::wchartType();
577 // see updateSingleExpr() why we move the value
578 var
->m_partialValue
= formatWCharPointer(var
->m_value
);
579 var
->m_value
.truncate(0);
580 tree
->m_updateStruct
.append(var
);
583 // add pointer pixmap to pointers
584 if (var
->m_varKind
== VarTree::VKpointer
) {
585 var
->setPixmap(tree
->m_pixPointer
);
590 QString
ExprWnd::formatWCharPointer(QString value
)
592 int pos
= value
.find(") ");
594 value
= value
.mid(pos
+2);
599 VarTree
* ExprWnd::topLevelExprByName(const char* name
)
603 KTreeViewItem
* item
= itemAt(path
);
605 return static_cast<VarTree
*>(item
);
608 VarTree
* ExprWnd::ptrMemberByName(VarTree
* v
, const QString
& name
)
610 // v must be a pointer variable, must have children
611 if (v
->m_varKind
!= VarTree::VKpointer
|| v
->childCount() == 0)
614 // the only child of v is the pointer value that represents the struct
615 KTreeViewItem
* item
= v
->getChild();
616 return memberByName(static_cast<VarTree
*>(item
), name
);
619 VarTree
* ExprWnd::memberByName(VarTree
* v
, const QString
& name
)
621 // search immediate children for name
622 KTreeViewItem
* item
= v
->getChild();
623 while (item
!= 0 && item
->getText() != name
)
624 item
= item
->getSibling();
627 return static_cast<VarTree
*>(item
);
629 // try in base classes
630 item
= v
->getChild();
632 static_cast<VarTree
*>(item
)->m_nameKind
== VarTree::NKtype
)
634 v
= memberByName(static_cast<VarTree
*>(item
), name
);
637 item
= item
->getSibling();
642 void ExprWnd::removeExpr(VarTree
* item
)
652 void ExprWnd::unhookSubtree(VarTree
* subTree
)
654 // must remove any pointers scheduled for update from the list
655 unhookSubtree(m_updatePtrs
, subTree
);
656 unhookSubtree(m_updateType
, subTree
);
657 unhookSubtree(m_updateStruct
, subTree
);
658 emit
removingItem(subTree
);
661 void ExprWnd::unhookSubtree(QList
<VarTree
>& list
, VarTree
* subTree
)
666 VarTree
* checkItem
= list
.first();
667 while (checkItem
!= 0) {
668 if (!subTree
->isAncestorEq(checkItem
)) {
669 // checkItem is not an item from subTree
671 checkItem
= list
.next();
673 // checkItem is an item from subTree
675 * If checkItem is the last item in the list, we need a special
676 * treatment, because remove()ing it steps the current item of
677 * the list in the "wrong" direction.
679 if (checkItem
== list
.getLast()) { // does not set current item
681 /* we deleted the last element, so we've finished */
685 /* remove() advanced already */
686 checkItem
= list
.current();
692 QString
ExprWnd::exprStringAt(int index
)
694 KTreeViewItem
* item
= itemAt(index
);
695 if (item
== 0) return QString(); /* paranoia */
696 VarTree
* expr
= static_cast<VarTree
*>(item
);
697 return expr
->computeExpr();
700 void ExprWnd::clearPendingUpdates()
702 m_updatePtrs
.clear();
703 m_updateType
.clear();
704 m_updateStruct
.clear();
707 VarTree
* ExprWnd::nextUpdatePtr()
709 VarTree
* ptr
= m_updatePtrs
.first();
711 m_updatePtrs
.remove();
716 VarTree
* ExprWnd::nextUpdateType()
718 VarTree
* ptr
= m_updateType
.first();
720 m_updateType
.remove();
725 VarTree
* ExprWnd::nextUpdateStruct()
727 VarTree
* ptr
= m_updateStruct
.first();
729 m_updateStruct
.remove();
734 void ExprWnd::paintCell(QPainter
* painter
, int row
, int col
)
737 KTreeView::paintCell(painter
, row
, col
);
739 VarTree
* item
= static_cast<VarTree
*>(itemAt(row
));
741 item
->paintValue(painter
);
746 int ExprWnd::cellWidth(int col
) const
749 return KTreeView::cellWidth(col
);
751 return maxValueWidth
;
755 void ExprWnd::updateValuesWidth()
758 forEveryVisibleItem(static_cast<KForEveryFunc
>(&getMaxValueWidth
), &maxW
);
759 maxValueWidth
= maxW
;
763 // called by updateValuesWidth() for each item in the visible list
764 bool ExprWnd::getMaxValueWidth(KTreeViewItem
* item
, void* user
)
766 int *maxW
= (int *)user
;
767 VarTree
* v
= static_cast<VarTree
*>(item
);
768 int w
= v
->valueWidth();
774 void ExprWnd::slotExpandOrCollapse(int)
779 void ExprWnd::editValue(int row
, const QString
& text
)
785 int w
= cellWidth(1);
786 int h
= cellHeight(row
);
787 QScrollBar
* sbV
= static_cast<QScrollBar
*>(child("table_sbV"));
790 * Make the edit widget at least 5 characters wide (but not wider than
791 * this widget). If less than half of this widget is used to display
792 * the text, scroll this widget so that half of it shows the text (or
793 * less than half of it if the text is shorter).
795 QFontMetrics metr
= m_edit
.font();
796 int wMin
= metr
.width("88888");
800 if (sbV
->isVisible()) // subtract width of scrollbar
801 wThis
-= sbV
->width();
802 if (x
>= wThis
/2 && // less than half the width displays text
803 x
+w
> wThis
) // not all text is visible
805 // scroll so that more text is visible
806 int wScroll
= QMIN(x
-wThis
/2, x
+w
-wThis
);
807 sbHor(xOffset()+wScroll
);
812 // don't let the edit move out at the left
816 // make the edit box as wide as the visible column
817 QRect
rect(x
,y
, wThis
-x
,h
);
818 m_edit
.setText(text
);
821 m_edit
.setGeometry(rect
);
822 m_edit
.m_finished
= false;
828 bool ExprWnd::isEditing() const
830 return m_edit
.isVisible();
834 ValueEdit::ValueEdit(ExprWnd
* parent
) :
835 QLineEdit(parent
, "valueedit")
839 lower(); // lower the window below scrollbars
840 connect(parent
, SIGNAL(selected(int)), SLOT(slotSelectionChanged()));
841 connect(parent
, SIGNAL(collapsed(int)), SLOT(slotSelectionChanged()));
842 connect(parent
, SIGNAL(expanded(int)), SLOT(slotSelectionChanged()));
843 connect(this, SIGNAL(done(int, const QString
&)),
844 parent
, SIGNAL(editValueCommitted(int, const QString
&)));
847 ValueEdit::~ValueEdit()
851 void ValueEdit::terminate(bool commit
)
853 TRACE(commit
?"ValueEdit::terminate(true)":"ValueEdit::terminate(false)");
857 hide(); // will call focusOutEvent, that's why we need m_finished
859 emit
done(m_row
, text());
864 void ValueEdit::keyPressEvent(QKeyEvent
*e
)
866 if(e
->key() == Qt::Key_Return
|| e
->key() == Qt::Key_Enter
)
868 else if(e
->key() == Qt::Key_Escape
)
871 QLineEdit::keyPressEvent(e
);
874 void ValueEdit::paintEvent(QPaintEvent
* e
)
876 QLineEdit::paintEvent(e
);
882 void ValueEdit::focusOutEvent(QFocusEvent
* ev
)
884 TRACE("ValueEdit::focusOutEvent");
885 QFocusEvent
* focusEv
= static_cast<QFocusEvent
*>(ev
);
886 // Don't let a RMB close the editor
887 if (focusEv
->reason() != QFocusEvent::Popup
&&
888 focusEv
->reason() != QFocusEvent::ActiveWindow
)
894 void ValueEdit::slotSelectionChanged()
896 TRACE("ValueEdit::slotSelectionChanged");