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(ExprValue
* v
) :
20 KTreeViewItem(v
->m_name
),
21 m_varKind(v
->m_varKind
),
22 m_nameKind(v
->m_nameKind
),
23 m_valueChanged(false),
26 m_exprIndexUseGuard(false),
29 setDelayedExpanding(m_varKind
== VKpointer
);
30 setExpanded(v
->m_initiallyExpanded
);
33 VarTree::VarTree(const QString
& name
) :
36 m_nameKind(VarTree::NKplain
),
37 m_valueChanged(false),
40 m_exprIndexUseGuard(false)
48 void VarTree::paintValue(QPainter
* p
)
51 int cellHeight
= height(p
->fontMetrics());
53 int textY
= (cellHeight
- p
->fontMetrics().height()) / 2 +
54 p
->fontMetrics().ascent();
59 // p->setBackgroundColor(cg.base());
60 p
->drawText(textX
, textY
, value(), value().length());
64 int VarTree::valueWidth()
67 return owner
->fontMetrics().width(value()) + 4;
70 QString
VarTree::computeExpr() const
72 assert(getParent() != 0);
77 // top-level items are special
78 if (getParent()->getParent() == 0)
82 VarTree
* par
= static_cast<VarTree
*>(getParent());
83 QString parentExpr
= par
->computeExpr();
85 /* don't add this item's name if this is a base class sub-item */
86 if (m_nameKind
== NKtype
) {
89 /* augment by this item's text */
91 /* if this is an address, dereference it */
92 if (m_nameKind
== NKaddress
) {
93 ASSERT(par
->m_varKind
== VKpointer
);
94 result
= "*" + parentExpr
;
97 switch (par
->m_varKind
) {
100 QString index
= getText();
102 // skip past the index
103 while (index
[i
].isDigit())
106 * Some array indices are actually ranges due to repeated array
107 * values. We use the first index in these cases.
109 if (index
[i
] != ']') {
110 // remove second index
111 index
.remove(i
, index
.length()-i
-1);
113 result
= "(" + parentExpr
+ ")" + index
;
117 result
= "(" + parentExpr
+ ")." + getText();
119 case VKsimple
: /* parent can't be simple */
120 case VKpointer
: /* handled in NKaddress */
121 case VKdummy
: /* can't occur at all */
123 result
= parentExpr
; /* paranoia */
129 bool VarTree::isToplevelExpr() const
131 return getParent() != 0 && getParent()->getParent() == 0;
134 bool VarTree::isAncestorEq(const VarTree
* child
) const
136 const KTreeViewItem
* c
= child
;
137 while (c
!= 0 && c
!= this) {
143 bool VarTree::updateValue(const QString
& newValue
)
145 // check whether the value changed
146 bool prevValueChanged
= m_valueChanged
;
147 m_valueChanged
= false;
148 if (value() != newValue
) {
150 m_valueChanged
= true;
153 * We must repaint the cell if the value changed. If it did not change,
154 * we still must repaint the cell if the value changed previously,
155 * because the color of the display must be changed (from red to
158 return m_valueChanged
|| prevValueChanged
;
161 void VarTree::inferTypesOfChildren(ProgramTypeTable
& typeTable
)
164 * Type inference works like this: We use type information of those
165 * children that have a type name in their name (base classes) or in
166 * their value (pointers)
169 // first recurse children
170 VarTree
* child
= firstChild();
172 child
->inferTypesOfChildren(typeTable
);
173 child
= child
->nextSibling();
176 // if this is a pointer, get the type from the value (less the pointer)
177 if (m_varKind
== VKpointer
) {
181 * wchart_t pointers must be treated as struct, because the array
182 * of characters is printed similar to how QStrings are decoded.
184 m_varKind
= VKstruct
;
185 setDelayedExpanding(false);
188 #ifndef I_know_a_way_to_do_this_cleanly
191 const char* p
= m_value
.data();
192 const char* start
= p
;
193 // the type of the pointer shows up in the value (sometimes)
194 if (p
== 0 || *p
!= '(')
196 skipNested(p
, '(', ')');
198 * We only recognize pointers to data "(int *)" but not pointers
199 * to functions "(void (*)())".
201 if (p
-start
< 3 && /* at least 3 chars necessary: (*) */
202 p
[-2] != '*') /* skip back before the closing paren */
206 const QString
& typeName
=
207 QString::fromLatin1(start
+1, p
-start
-3) // minus 3 chars
209 m_type
= typeTable
.lookup(typeName
);
211 m_type
= TypeInfo::unknownType();
214 } else if (m_varKind
== VKstruct
) {
215 // check if this is a base class part
216 if (m_nameKind
== NKtype
) {
217 const QString
& typeName
=
218 text
.mid(1, text
.length()-2); // strip < and >
219 m_type
= typeTable
.lookup(typeName
);
221 /* if we don't have a type yet, get it from the base class */
223 m_type
= inferTypeFromBaseClass();
225 * If there is a known type now, it is the one from the
226 * first base class whose type we know.
231 * If we still don't have a type, the type is really unknown.
234 m_type
= TypeInfo::unknownType();
238 * This is not a base class part. We don't assign a type so
239 * that later we can ask gdb.
244 // the value contains the pointer type in parenthesis
245 bool VarTree::isWcharT() const
247 return value().startsWith("(const wchar_t *)") ||
248 value().startsWith("(wchar_t *)");
252 * Get the type of the first base class whose type we know.
254 TypeInfo
* VarTree::inferTypeFromBaseClass()
256 if (m_varKind
== VKstruct
) {
257 VarTree
* child
= firstChild();
259 // only check base class parts (i.e. type names)
260 child
->m_nameKind
== NKtype
)
262 if (child
->m_type
!= 0 &&
263 child
->m_type
!= TypeInfo::unknownType())
266 return child
->m_type
;
268 child
= child
->nextSibling();
274 ExprValue::ExprValue(const QString
& name
, VarTree::NameKind aKind
) :
276 m_varKind(VarTree::VKsimple
),
280 m_initiallyExpanded(false)
284 ExprValue::~ExprValue()
290 void ExprValue::appendChild(ExprValue
* newChild
)
295 // walk chain of children to find the last one
296 ExprValue
* last
= m_child
;
297 while (last
->m_next
!= 0)
299 last
->m_next
= newChild
;
301 newChild
->m_next
= 0; // just to be sure
304 uint
ExprValue::childCount() const
307 ExprValue
* c
= m_child
;
317 ExprWnd::ExprWnd(QWidget
* parent
, const char* name
) :
318 KTreeView(parent
, name
),
324 connect(this, SIGNAL(expanded(int)), SLOT(slotExpandOrCollapse(int)));
325 connect(this, SIGNAL(collapsed(int)), SLOT(slotExpandOrCollapse(int)));
327 m_pixPointer
= UserIcon("pointer.xpm");
328 if (m_pixPointer
.isNull())
329 TRACE("Can't load pointer.xpm");
336 void ExprWnd::exprList(QStrList
& exprs
)
338 // ASSERT(exprs does deep-copies)
340 for (item
= firstChild(); item
!= 0; item
= item
->nextSibling()) {
341 exprs
.append(item
->getText());
345 VarTree
* ExprWnd::insertExpr(ExprValue
* expr
, ProgramTypeTable
& typeTable
)
347 // append a new dummy expression
348 VarTree
* display
= new VarTree(expr
->m_name
);
351 // replace it right away
352 updateExpr(display
, expr
, typeTable
);
356 void ExprWnd::updateExpr(ExprValue
* expr
, ProgramTypeTable
& typeTable
)
358 // search the root variable
359 VarTree
* item
= firstChild();
360 while (item
!= 0 && item
->getText() != expr
->m_name
)
361 item
= item
->nextSibling();
366 if (updateExprRec(item
, expr
, typeTable
)) {
367 updateVisibleItems();
371 collectUnknownTypes(item
);
374 void ExprWnd::updateExpr(VarTree
* display
, ExprValue
* newValues
, ProgramTypeTable
& typeTable
)
376 if (updateExprRec(display
, newValues
, typeTable
) &&
377 display
->isVisible())
379 updateVisibleItems();
383 collectUnknownTypes(display
);
387 * returns true if there's a visible change
389 bool ExprWnd::updateExprRec(VarTree
* display
, ExprValue
* newValues
, ProgramTypeTable
& typeTable
)
391 bool isExpanded
= display
->isExpanded();
394 * If we are updating a pointer without children by a dummy, we don't
395 * collapse it, but simply insert the new children. This happens when a
396 * pointer has just been expanded by the user.
398 if (display
->m_varKind
== VarTree::VKpointer
&&
399 display
->childCount() == 0 &&
400 newValues
->m_varKind
== VarTree::VKdummy
)
402 replaceChildren(display
, newValues
);
403 return isExpanded
; /* no visible change if not expanded */
407 * If the display and newValues have different kind or if their number
408 * of children is different, replace the whole sub-tree.
410 if (// the next two lines mean: not(m_varKind remains unchanged)
411 !(newValues
->m_varKind
== VarTree::VKdummy
||
412 display
->m_varKind
== newValues
->m_varKind
)
414 (display
->childCount() != newValues
->childCount() &&
416 * If this is a pointer and newValues doesn't have children, we
417 * don't replace the sub-tree; instead, below we mark this
418 * sub-tree for requiring an update.
420 (display
->m_varKind
!= VarTree::VKpointer
||
421 newValues
->m_child
!= 0)))
424 collapseSubTree(display
, false);
427 // since children changed, it is likely that the type has also changed
428 display
->m_type
= 0; /* will re-evaluate the type */
430 // display the new value
431 updateSingleExpr(display
, newValues
);
432 replaceChildren(display
, newValues
);
434 // update the m_varKind
435 if (newValues
->m_varKind
!= VarTree::VKdummy
) {
436 display
->m_varKind
= newValues
->m_varKind
;
437 display
->setDelayedExpanding(newValues
->m_varKind
== VarTree::VKpointer
);
440 // get some types (after the new m_varKind has been set!)
441 display
->inferTypesOfChildren(typeTable
);
443 // (note that the new value might not have a sub-tree at all)
444 return display
->m_valueChanged
|| isExpanded
; /* no visible change if not expanded */
447 // display the new value
448 updateSingleExpr(display
, newValues
);
451 * If this is an expanded pointer, record it for being updated.
453 if (display
->m_varKind
== VarTree::VKpointer
) {
455 // if newValues is a dummy, we have already updated this pointer
456 newValues
->m_varKind
!= VarTree::VKdummy
)
458 m_updatePtrs
.append(display
);
461 * If the visible sub-tree has children, but newValues doesn't, we
464 if (newValues
->m_child
== 0) {
465 return display
->m_valueChanged
;
469 ASSERT(display
->childCount() == newValues
->childCount());
472 bool childChanged
= false;
474 VarTree
* vDisplay
= display
->firstChild();
475 ExprValue
* vNew
= newValues
->m_child
;
476 while (vDisplay
!= 0) {
477 // check whether the names are the same
478 if (vDisplay
->getText() != vNew
->m_name
) {
480 vDisplay
->setText(vNew
->m_name
);
481 int i
= itemRow(vDisplay
);
483 updateCell(i
, 0, true);
488 if (updateExprRec(vDisplay
, vNew
, typeTable
)) {
491 vDisplay
= vDisplay
->nextSibling();
495 // update of children propagates only if this node is expanded
496 return display
->m_valueChanged
|| (display
->isExpanded() && childChanged
);
499 void ExprWnd::updateSingleExpr(VarTree
* display
, ExprValue
* newValue
)
502 * If newValues is a VKdummy, we are only interested in its children.
503 * No need to update anything here.
505 if (newValue
->m_varKind
== VarTree::VKdummy
) {
510 * If this node is a struct and we know its type then don't update its
511 * value now. This is a node for which we know how to find a nested
512 * value. So register the node for an update.
514 * wchar_t types are also treated specially here: We consider them
515 * as struct (has been set in inferTypesOfChildren()).
517 if (display
->m_varKind
== VarTree::VKstruct
&&
518 display
->m_type
!= 0 &&
519 display
->m_type
!= TypeInfo::unknownType())
521 ASSERT(newValue
->m_varKind
== VarTree::VKstruct
);
522 if (display
->m_type
== TypeInfo::wchartType())
525 * We do not copy the new pointer value to the destination right
526 * away, but consider it as the first part of the nested value.
527 * Then the display will change its color only when the new value
530 display
->m_partialValue
= formatWCharPointer(newValue
->m_value
);
533 display
->m_partialValue
= display
->m_type
->m_displayString
[0];
534 m_updateStruct
.append(display
);
538 if (display
->updateValue(newValue
->m_value
)) {
539 int i
= itemRow(display
);
541 updateCell(i
, 1, true);
547 void ExprWnd::updateStructValue(VarTree
* display
)
549 ASSERT(display
->m_varKind
== VarTree::VKstruct
);
551 if (display
->updateValue(display
->m_partialValue
)) {
552 int i
= itemRow(display
);
555 updateCell(i
, 1, true);
559 display
->m_partialValue
= "";
560 display
->m_exprIndex
= -1;
563 void ExprWnd::replaceChildren(VarTree
* display
, ExprValue
* newValues
)
565 ASSERT(display
->childCount() == 0 || display
->m_varKind
!= VarTree::VKsimple
);
567 // delete all children of display
568 while (VarTree
* c
= display
->firstChild()) {
570 display
->removeChild(c
);
573 // insert copies of the newValues
574 for (ExprValue
* v
= newValues
->m_child
; v
!= 0; v
= v
->m_next
)
576 VarTree
* vNew
= new VarTree(v
);
577 display
->appendChild(vNew
);
579 replaceChildren(vNew
, v
);
583 void ExprWnd::collectUnknownTypes(VarTree
* var
)
586 * forEveryItem does not scan the root item itself. So we must do it
589 ASSERT(var
->m_varKind
!= VarTree::VKpointer
|| var
->m_nameKind
!= VarTree::NKtype
);
590 if (var
->m_type
== 0 &&
591 var
->m_varKind
== VarTree::VKstruct
&&
592 var
->m_nameKind
!= VarTree::NKtype
)
594 if (!var
->isWcharT())
596 /* this struct node doesn't have a type yet: register it */
597 m_updateType
.append(var
);
601 var
->m_type
= TypeInfo::wchartType();
602 // see updateSingleExpr() why we move the value
603 var
->m_partialValue
= formatWCharPointer(var
->value());
604 var
->setValue(QString());
605 m_updateStruct
.append(var
);
609 // add pointer pixmap to pointers
610 if (var
->m_varKind
== VarTree::VKpointer
) {
611 var
->setPixmap(m_pixPointer
);
614 forEveryItem(collectUnknownTypes
, this, var
);
617 bool ExprWnd::collectUnknownTypes(KTreeViewItem
* item
, void* user
)
619 VarTree
* var
= static_cast<VarTree
*>(item
);
620 ExprWnd
* tree
= static_cast<ExprWnd
*>(user
);
621 ASSERT(var
->m_varKind
!= VarTree::VKpointer
|| var
->m_nameKind
!= VarTree::NKtype
);
622 if (var
->m_type
== 0 &&
623 var
->m_varKind
== VarTree::VKstruct
&&
624 var
->m_nameKind
!= VarTree::NKtype
)
626 if (!var
->isWcharT())
628 /* this struct node doesn't have a type yet: register it */
629 tree
->m_updateType
.append(var
);
633 var
->m_type
= TypeInfo::wchartType();
634 // see updateSingleExpr() why we move the value
635 var
->m_partialValue
= formatWCharPointer(var
->value());
636 var
->setValue(QString());
637 tree
->m_updateStruct
.append(var
);
640 // add pointer pixmap to pointers
641 if (var
->m_varKind
== VarTree::VKpointer
) {
642 var
->setPixmap(tree
->m_pixPointer
);
647 QString
ExprWnd::formatWCharPointer(QString value
)
649 int pos
= value
.find(") ");
651 value
= value
.mid(pos
+2);
656 VarTree
* ExprWnd::topLevelExprByName(const char* name
)
658 VarTree
* item
= firstChild();
659 while (item
!= 0 && item
->getText() != name
)
660 item
= item
->nextSibling();
665 VarTree
* ExprWnd::ptrMemberByName(VarTree
* v
, const QString
& name
)
667 // v must be a pointer variable, must have children
668 if (v
->m_varKind
!= VarTree::VKpointer
|| v
->childCount() == 0)
671 // the only child of v is the pointer value that represents the struct
672 VarTree
* item
= v
->firstChild();
673 return memberByName(item
, name
);
676 VarTree
* ExprWnd::memberByName(VarTree
* v
, const QString
& name
)
678 // search immediate children for name
679 VarTree
* item
= v
->firstChild();
680 while (item
!= 0 && item
->getText() != name
)
681 item
= item
->nextSibling();
686 // try in base classes
687 item
= v
->firstChild();
689 item
->m_nameKind
== VarTree::NKtype
)
691 v
= memberByName(item
, name
);
694 item
= item
->nextSibling();
699 void ExprWnd::removeExpr(VarTree
* item
)
709 void ExprWnd::unhookSubtree(VarTree
* subTree
)
711 // must remove any pointers scheduled for update from the list
712 unhookSubtree(m_updatePtrs
, subTree
);
713 unhookSubtree(m_updateType
, subTree
);
714 unhookSubtree(m_updateStruct
, subTree
);
715 emit
removingItem(subTree
);
718 void ExprWnd::unhookSubtree(QList
<VarTree
>& list
, VarTree
* subTree
)
723 VarTree
* checkItem
= list
.first();
724 while (checkItem
!= 0) {
725 if (!subTree
->isAncestorEq(checkItem
)) {
726 // checkItem is not an item from subTree
728 checkItem
= list
.next();
730 // checkItem is an item from subTree
732 * If checkItem is the last item in the list, we need a special
733 * treatment, because remove()ing it steps the current item of
734 * the list in the "wrong" direction.
736 if (checkItem
== list
.getLast()) { // does not set current item
738 /* we deleted the last element, so we've finished */
742 /* remove() advanced already */
743 checkItem
= list
.current();
749 void ExprWnd::clearPendingUpdates()
751 m_updatePtrs
.clear();
752 m_updateType
.clear();
753 m_updateStruct
.clear();
756 VarTree
* ExprWnd::nextUpdatePtr()
758 VarTree
* ptr
= m_updatePtrs
.first();
760 m_updatePtrs
.remove();
765 VarTree
* ExprWnd::nextUpdateType()
767 VarTree
* ptr
= m_updateType
.first();
769 m_updateType
.remove();
774 VarTree
* ExprWnd::nextUpdateStruct()
776 VarTree
* ptr
= m_updateStruct
.first();
778 m_updateStruct
.remove();
783 void ExprWnd::paintCell(QPainter
* painter
, int row
, int col
)
786 KTreeView::paintCell(painter
, row
, col
);
788 VarTree
* item
= static_cast<VarTree
*>(itemAt(row
));
790 item
->paintValue(painter
);
795 int ExprWnd::cellWidth(int col
) const
798 return KTreeView::cellWidth(col
);
800 return maxValueWidth
;
804 void ExprWnd::updateValuesWidth()
807 forEveryVisibleItem(static_cast<KForEveryFunc
>(&getMaxValueWidth
), &maxW
);
808 maxValueWidth
= maxW
;
812 // called by updateValuesWidth() for each item in the visible list
813 bool ExprWnd::getMaxValueWidth(KTreeViewItem
* item
, void* user
)
815 int *maxW
= (int *)user
;
816 VarTree
* v
= static_cast<VarTree
*>(item
);
817 int w
= v
->valueWidth();
823 void ExprWnd::slotExpandOrCollapse(int)
828 void ExprWnd::editValue(int row
, const QString
& text
)
831 m_edit
= new ValueEdit(this);
837 int w
= cellWidth(1);
838 int h
= cellHeight(row
);
839 QScrollBar
* sbV
= static_cast<QScrollBar
*>(child("table_sbV"));
842 * Make the edit widget at least 5 characters wide (but not wider than
843 * this widget). If less than half of this widget is used to display
844 * the text, scroll this widget so that half of it shows the text (or
845 * less than half of it if the text is shorter).
847 QFontMetrics metr
= m_edit
->font();
848 int wMin
= metr
.width("88888");
852 if (sbV
->isVisible()) // subtract width of scrollbar
853 wThis
-= sbV
->width();
854 if (x
>= wThis
/2 && // less than half the width displays text
855 x
+w
> wThis
) // not all text is visible
857 // scroll so that more text is visible
858 int wScroll
= QMIN(x
-wThis
/2, x
+w
-wThis
);
859 sbHor(xOffset()+wScroll
);
864 // don't let the edit move out at the left
868 // make the edit box as wide as the visible column
869 QRect
rect(x
,y
, wThis
-x
,h
);
870 m_edit
->setText(text
);
873 m_edit
->setGeometry(rect
);
874 m_edit
->m_finished
= false;
880 bool ExprWnd::isEditing() const
882 return m_edit
!= 0 && m_edit
->isVisible();
886 ValueEdit::ValueEdit(ExprWnd
* parent
) :
887 QLineEdit(parent
, "valueedit")
891 lower(); // lower the window below scrollbars
892 connect(parent
, SIGNAL(selected(int)), SLOT(slotSelectionChanged()));
893 connect(parent
, SIGNAL(collapsed(int)), SLOT(slotSelectionChanged()));
894 connect(parent
, SIGNAL(expanded(int)), SLOT(slotSelectionChanged()));
895 connect(this, SIGNAL(done(int, const QString
&)),
896 parent
, SIGNAL(editValueCommitted(int, const QString
&)));
899 ValueEdit::~ValueEdit()
903 void ValueEdit::terminate(bool commit
)
905 TRACE(commit
?"ValueEdit::terminate(true)":"ValueEdit::terminate(false)");
909 hide(); // will call focusOutEvent, that's why we need m_finished
911 emit
done(m_row
, text());
916 void ValueEdit::keyPressEvent(QKeyEvent
*e
)
918 if(e
->key() == Qt::Key_Return
|| e
->key() == Qt::Key_Enter
)
920 else if(e
->key() == Qt::Key_Escape
)
923 QLineEdit::keyPressEvent(e
);
926 void ValueEdit::paintEvent(QPaintEvent
* e
)
928 QLineEdit::paintEvent(e
);
934 void ValueEdit::focusOutEvent(QFocusEvent
* ev
)
936 TRACE("ValueEdit::focusOutEvent");
937 QFocusEvent
* focusEv
= static_cast<QFocusEvent
*>(ev
);
938 // Don't let a RMB close the editor
939 if (focusEv
->reason() != QFocusEvent::Popup
&&
940 focusEv
->reason() != QFocusEvent::ActiveWindow
)
946 void ValueEdit::slotSelectionChanged()
948 TRACE("ValueEdit::slotSelectionChanged");