Make ProgramTypeTable related TypeInfo infrastructure const-correct.
[kdbg.git] / kdbg / exprwnd.cpp
blob665de9827685f2be96905d872bccae3e14306cff
1 /*
2 * Copyright Johannes Sixt
3 * This file is licensed under the GNU General Public License Version 2.
4 * See the file COPYING in the toplevel directory of the source directory.
5 */
7 #include "exprwnd.h"
8 #include "exprwnd.moc"
9 #include "typetable.h"
10 #include <QHeaderView>
11 #include <QStringList>
12 #include <QPainter>
13 #include <QPaintEvent>
14 #include <QFocusEvent>
15 #include <QKeyEvent>
16 #include <QScrollBar>
17 #include <kiconloader.h> /* icons */
18 #include <klocale.h> /* i18n */
19 #include "mydebug.h"
21 VarTree::VarTree(VarTree* parent, ExprValue* v) :
22 QTreeWidgetItem(parent),
23 m_varKind(v->m_varKind),
24 m_nameKind(v->m_nameKind),
25 m_type(0),
26 m_exprIndex(0),
27 m_exprIndexUseGuard(false),
28 m_baseValue(v->m_value),
29 m_baseChanged(false),
30 m_structChanged(false)
32 setText(v->m_name);
33 updateValueText();
34 if (v->m_initiallyExpanded || m_varKind == VarTree::VKpointer)
35 setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
36 else
37 setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicator);
38 setExpanded(v->m_initiallyExpanded);
41 VarTree::VarTree(ExprWnd* parent, const QString& name) :
42 QTreeWidgetItem(parent),
43 m_varKind(VKsimple),
44 m_nameKind(VarTree::NKplain),
45 m_type(0),
46 m_exprIndex(0),
47 m_exprIndexUseGuard(false),
48 m_baseChanged(false),
49 m_structChanged(false)
51 setText(name);
54 VarTree::~VarTree()
58 QString VarTree::computeExpr() const
60 // top-level items are special
61 if (isToplevelExpr())
62 return getText();
64 // get parent expr
65 VarTree* par = static_cast<VarTree*>(parent());
66 QString parentExpr = par->computeExpr();
68 // skip this item's name if it is a base class or anonymous struct or union
69 if (m_nameKind == NKtype || m_nameKind == NKanonymous) {
70 return parentExpr;
72 /* augment by this item's text */
73 QString result;
74 /* if this is an address, dereference it */
75 if (m_nameKind == NKaddress) {
76 ASSERT(par->m_varKind == VKpointer);
77 result = "*" + parentExpr;
78 return result;
80 switch (par->m_varKind) {
81 case VKarray:
83 QString index = getText();
84 int i = 1;
85 // skip past the index
86 while (index[i].isDigit())
87 i++;
89 * Some array indices are actually ranges due to repeated array
90 * values. We use the first index in these cases.
92 if (index[i] != ']') {
93 // remove second index
94 index.remove(i, index.length()-i-1);
96 result = "(" + parentExpr + ")" + index;
98 break;
99 case VKstruct:
100 result = "(" + parentExpr + ")." + getText();
101 break;
102 case VKsimple: /* parent can't be simple */
103 case VKpointer: /* handled in NKaddress */
104 case VKdummy: /* can't occur at all */
105 ASSERT(false);
106 result = parentExpr; /* paranoia */
107 break;
109 return result;
112 bool VarTree::isToplevelExpr() const
114 return parent() == 0;
117 bool VarTree::isAncestorEq(const VarTree* child) const
119 const QTreeWidgetItem* c = child;
120 while (c != 0 && c != this) {
121 c = c->parent();
123 return c != 0;
126 bool VarTree::updateValue(const QString& newValue)
128 // check whether the value changed
129 bool prevValueChanged = m_baseChanged;
130 if ((m_baseChanged = m_baseValue != newValue)) {
131 m_baseValue = newValue;
132 updateValueText();
133 setForeground(1, QBrush(QColor(Qt::red)));
134 } else if (prevValueChanged) {
135 setForeground(1, treeWidget()->palette().text());
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
141 * black).
143 return m_baseChanged || prevValueChanged;
146 bool VarTree::updateStructValue(const QString& newValue)
148 // check whether the value changed
149 bool prevValueChanged = m_structChanged;
150 if ((m_structChanged = m_structValue != newValue)) {
151 m_structValue = newValue;
152 updateValueText();
153 setForeground(1, QBrush(QColor(Qt::red)));
154 } else if (prevValueChanged) {
155 setForeground(1, treeWidget()->palette().text());
158 * We must repaint the cell if the value changed. If it did not change,
159 * we still must repaint the cell if the value changed previously,
160 * because the color of the display must be changed (from red to
161 * black).
163 return m_structChanged || prevValueChanged;
166 void VarTree::updateValueText()
168 if (m_baseValue.isEmpty()) {
169 setText(1, m_structValue);
170 } else if (m_structValue.isEmpty()) {
171 setText(1, m_baseValue);
172 } else {
173 setText(1, m_baseValue + " " + m_structValue);
177 void VarTree::inferTypesOfChildren(ProgramTypeTable& typeTable)
180 * Type inference works like this: We use type information of those
181 * children that have a type name in their name (base classes) or in
182 * their value (pointers)
185 // first recurse children
186 for (int i = 0; i < childCount(); i++)
188 child(i)->inferTypesOfChildren(typeTable);
191 // if this is a pointer, get the type from the value (less the pointer)
192 if (m_varKind == VKpointer) {
193 if (isWcharT())
196 * wchart_t pointers must be treated as struct, because the array
197 * of characters is printed similar to how QStrings are decoded.
199 m_varKind = VKstruct;
200 setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicator);
202 // don't know how to do this cleanly
203 } else if (m_varKind == VKstruct) {
204 // check if this is a base class part
205 if (m_nameKind == NKtype) {
206 const QString& typeName =
207 getText().mid(1, getText().length()-2); // strip < and >
208 m_type = typeTable.lookup(typeName);
210 /* if we don't have a type yet, get it from the base class */
211 if (m_type == 0) {
212 m_type = inferTypeFromBaseClass();
214 * If there is a known type now, it is the one from the
215 * first base class whose type we know.
220 * If we still don't have a type, the type is really unknown.
222 if (m_type == 0) {
223 m_type = TypeInfo::unknownType();
225 } // else
227 * This is not a base class part. We don't assign a type so
228 * that later we can ask gdb.
233 // the value contains the pointer type in parenthesis
234 bool VarTree::isWcharT() const
236 return value().startsWith("(const wchar_t *)") ||
237 value().startsWith("(wchar_t *)");
241 * Get the type of the first base class whose type we know.
243 const TypeInfo* VarTree::inferTypeFromBaseClass()
245 if (m_varKind == VKstruct) {
246 for (int i = 0; i < childCount(); i++)
248 VarTree* child = VarTree::child(i);
249 // only check base class parts (i.e. type names)
250 if (child->m_nameKind != NKtype)
251 break;
252 if (child->m_type != 0 &&
253 child->m_type != TypeInfo::unknownType())
255 // got a type!
256 return child->m_type;
260 return 0;
263 ExprValue::ExprValue(const QString& name, VarTree::NameKind aKind) :
264 m_name(name),
265 m_varKind(VarTree::VKsimple),
266 m_nameKind(aKind),
267 m_child(0),
268 m_next(0),
269 m_initiallyExpanded(false)
273 ExprValue::~ExprValue()
275 delete m_child;
276 delete m_next;
279 void ExprValue::appendChild(ExprValue* newChild)
281 if (m_child == 0) {
282 m_child = newChild;
283 } else {
284 // walk chain of children to find the last one
285 ExprValue* last = m_child;
286 while (last->m_next != 0)
287 last = last->m_next;
288 last->m_next = newChild;
290 newChild->m_next = 0; // just to be sure
293 int ExprValue::childCount() const
295 int i = 0;
296 ExprValue* c = m_child;
297 while (c) {
298 ++i;
299 c = c->m_next;
301 return i;
306 ExprWnd::ExprWnd(QWidget* parent, const QString& colHeader) :
307 QTreeWidget(parent),
308 m_edit(0)
310 QTreeWidgetItem* pHeaderItem = new QTreeWidgetItem();
311 pHeaderItem->setText(0, colHeader);
312 pHeaderItem->setText(1, i18n("Value"));
313 setHeaderItem(pHeaderItem);
314 header()->setResizeMode(0, QHeaderView::Interactive);
315 header()->setResizeMode(1, QHeaderView::Interactive);
317 setSortingEnabled(false); // do not sort items
318 setRootIsDecorated(true);
319 setAllColumnsShowFocus(true);
321 m_pixPointer = UserIcon("pointer.xpm");
322 if (m_pixPointer.isNull())
323 TRACE("Can't load pointer.xpm");
326 ExprWnd::~ExprWnd()
330 QStringList ExprWnd::exprList() const
332 QStringList exprs;
333 for (int i = 0; i < topLevelItemCount(); i++)
335 exprs.append(topLevelItem(i)->getText());
337 return exprs;
340 VarTree* ExprWnd::insertExpr(ExprValue* expr, ProgramTypeTable& typeTable)
342 // append a new dummy expression
343 VarTree* display = new VarTree(this, expr->m_name);
345 // replace it right away
346 updateExpr(display, expr, typeTable);
347 return display;
350 void ExprWnd::updateExpr(ExprValue* expr, ProgramTypeTable& typeTable)
352 // search the root variable
353 VarTree* item = 0;
354 for (int i = 0; i < topLevelItemCount(); i++)
356 if (topLevelItem(i)->getText() == expr->m_name) {
357 item = topLevelItem(i);
358 break;
361 if (item == 0) {
362 return;
364 // now update it
365 updateExprRec(item, expr, typeTable);
366 collectUnknownTypes(item);
369 void ExprWnd::updateExpr(VarTree* display, ExprValue* newValues, ProgramTypeTable& typeTable)
371 updateExprRec(display, newValues, typeTable);
372 collectUnknownTypes(display);
376 * returns true if there's a visible change
378 void ExprWnd::updateExprRec(VarTree* display, ExprValue* newValues, ProgramTypeTable& typeTable)
380 bool isExpanded = display->isExpanded();
383 * If we are updating a pointer without children by a dummy, we don't
384 * collapse it, but simply insert the new children. This happens when a
385 * pointer has just been expanded by the user.
387 if (display->m_varKind == VarTree::VKpointer &&
388 display->childCount() == 0 &&
389 newValues->m_varKind == VarTree::VKdummy)
391 replaceChildren(display, newValues);
392 return;
396 * If the display and newValues have different kind or if their number
397 * of children is different, replace the whole sub-tree.
399 if (// the next two lines mean: not(m_varKind remains unchanged)
400 !(newValues->m_varKind == VarTree::VKdummy ||
401 display->m_varKind == newValues->m_varKind)
403 (display->childCount() != newValues->childCount() &&
405 * If this is a pointer and newValues doesn't have children, we
406 * don't replace the sub-tree; instead, below we mark this
407 * sub-tree for requiring an update.
409 (display->m_varKind != VarTree::VKpointer ||
410 newValues->m_child != 0)))
412 if (isExpanded) {
413 display->setExpanded(false);
416 // since children changed, it is likely that the type has also changed
417 display->m_type = 0; /* will re-evaluate the type */
419 // display the new value
420 updateSingleExpr(display, newValues);
421 replaceChildren(display, newValues);
423 // update the m_varKind
424 if (newValues->m_varKind != VarTree::VKdummy) {
425 display->m_varKind = newValues->m_varKind;
426 switch (display->m_varKind) {
427 case VarTree::VKpointer:
428 case VarTree::VKstruct:
429 display->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
430 break;
431 default:
432 display->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicator);
433 break;
437 // get some types (after the new m_varKind has been set!)
438 display->inferTypesOfChildren(typeTable);
440 // (note that the new value might not have a sub-tree at all)
441 return;
444 // display the new value
445 updateSingleExpr(display, newValues);
448 * If this is an expanded pointer, record it for being updated.
450 if (display->m_varKind == VarTree::VKpointer) {
451 if (isExpanded &&
452 // if newValues is a dummy, we have already updated this pointer
453 newValues->m_varKind != VarTree::VKdummy)
455 m_updatePtrs.push_back(display);
458 * If the visible sub-tree has children, but newValues doesn't, we
459 * can stop here.
461 if (newValues->m_child == 0) {
462 return;
466 ASSERT(display->childCount() == newValues->childCount());
468 // go for children
469 ExprValue* vNew = newValues->m_child;
470 for (int i = 0; i < display->childCount(); i++)
472 VarTree* vDisplay = display->child(i);
473 // check whether the names are the same
474 if (vDisplay->getText() != vNew->m_name) {
475 // set new name
476 vDisplay->setText(vNew->m_name);
478 // recurse
479 updateExprRec(vDisplay, vNew, typeTable);
481 vNew = vNew->m_next;
485 void ExprWnd::updateSingleExpr(VarTree* display, ExprValue* newValue)
488 * If newValues is a VKdummy, we are only interested in its children.
489 * No need to update anything here.
491 if (newValue->m_varKind == VarTree::VKdummy) {
492 return;
496 * If this node is a struct and we know its type then we know how to
497 * find a nested value. So register the node for an update.
499 * wchar_t types are also treated specially here: We consider them
500 * as struct (has been set in inferTypesOfChildren()).
502 if (display->m_varKind == VarTree::VKstruct &&
503 display->m_type != 0 &&
504 display->m_type != TypeInfo::unknownType())
506 ASSERT(newValue->m_varKind == VarTree::VKstruct);
507 if (display->m_type == TypeInfo::wchartType())
509 display->m_partialValue = "L";
511 else
512 display->m_partialValue = display->m_type->m_displayString[0];
513 m_updateStruct.push_back(display);
516 display->updateValue(newValue->m_value);
519 void ExprWnd::updateStructValue(VarTree* display)
521 ASSERT(display->m_varKind == VarTree::VKstruct);
523 display->updateStructValue(display->m_partialValue);
524 // reset the value
525 display->m_partialValue = "";
526 display->m_exprIndex = -1;
529 void ExprWnd::replaceChildren(VarTree* display, ExprValue* newValues)
531 ASSERT(display->childCount() == 0 || display->m_varKind != VarTree::VKsimple);
533 // delete all children of display
534 while (VarTree* c = display->child(0)) {
535 unhookSubtree(c);
536 delete c;
538 // insert copies of the newValues
539 for (ExprValue* v = newValues->m_child; v != 0; v = v->m_next)
541 VarTree* vNew = new VarTree(display, v);
542 // recurse
543 replaceChildren(vNew, v);
547 void ExprWnd::collectUnknownTypes(VarTree* var)
549 QTreeWidgetItemIterator i(var);
550 for (; *i; ++i)
552 checkUnknownType(static_cast<VarTree*>(*i));
556 void ExprWnd::checkUnknownType(VarTree* var)
558 ASSERT(var->m_varKind != VarTree::VKpointer || var->m_nameKind != VarTree::NKtype);
559 if (var->m_type == 0 &&
560 var->m_varKind == VarTree::VKstruct &&
561 var->m_nameKind != VarTree::NKtype &&
562 var->m_nameKind != VarTree::NKanonymous)
564 if (!var->isWcharT())
566 /* this struct node doesn't have a type yet: register it */
567 m_updateType.push_back(var);
569 else
571 var->m_type = TypeInfo::wchartType();
572 var->m_partialValue = "L";
573 m_updateStruct.push_back(var);
576 // add pointer pixmap to pointers
577 if (var->m_varKind == VarTree::VKpointer) {
578 var->setPixmap(m_pixPointer);
582 QString ExprWnd::formatWCharPointer(QString value)
584 int pos = value.find(") ");
585 if (pos > 0)
586 value = value.mid(pos+2);
587 return value + " L";
591 VarTree* ExprWnd::topLevelExprByName(const QString& name) const
593 for (int i = 0; i < topLevelItemCount(); i++)
595 if (topLevelItem(i)->getText() == name)
596 return topLevelItem(i);
598 return 0;
601 VarTree* ExprWnd::ptrMemberByName(VarTree* v, const QString& name)
603 // v must be a pointer variable, must have children
604 if (v->m_varKind != VarTree::VKpointer || v->childCount() == 0)
605 return 0;
607 // the only child of v is the pointer value that represents the struct
608 VarTree* item = v->child(0);
609 return memberByName(item, name);
612 VarTree* ExprWnd::memberByName(VarTree* v, const QString& name)
614 // search immediate children for name
615 for (int i = 0; i < v->childCount(); i++)
617 if (v->child(i)->getText() == name)
618 return v->child(i);
621 // try in base classes and members that are anonymous structs or unions
622 for (int i = 0; i < v->childCount(); i++)
624 VarTree* item = v->child(i);
625 if (item->m_nameKind == VarTree::NKtype ||
626 item->m_nameKind == VarTree::NKanonymous)
628 item = memberByName(item, name);
629 if (item != 0)
630 return item;
633 return 0;
636 void ExprWnd::removeExpr(VarTree* item)
638 unhookSubtree(item);
640 delete item;
643 void ExprWnd::unhookSubtree(VarTree* subTree)
645 // must remove any pointers scheduled for update from the list
646 unhookSubtree(m_updatePtrs, subTree);
647 unhookSubtree(m_updateType, subTree);
648 unhookSubtree(m_updateStruct, subTree);
649 emit removingItem(subTree);
652 void ExprWnd::unhookSubtree(std::list<VarTree*>& list, VarTree* subTree)
654 if (subTree == 0)
655 return;
657 std::list<VarTree*>::iterator i = list.begin();
658 while (i != list.end()) {
659 std::list<VarTree*>::iterator checkItem = i;
660 ++i;
661 if (subTree->isAncestorEq(*checkItem)) {
662 // checkItem is an item from subTree
663 list.erase(checkItem);
668 void ExprWnd::clearPendingUpdates()
670 m_updatePtrs.clear();
671 m_updateType.clear();
672 m_updateStruct.clear();
675 VarTree* ExprWnd::nextUpdatePtr()
677 VarTree* ptr = 0;
678 if (!m_updatePtrs.empty()) {
679 ptr = m_updatePtrs.front();
680 m_updatePtrs.pop_front();
682 return ptr;
685 VarTree* ExprWnd::nextUpdateType()
687 VarTree* ptr = 0;
688 if (!m_updateType.empty()) {
689 ptr = m_updateType.front();
690 m_updateType.pop_front();
692 return ptr;
695 VarTree* ExprWnd::nextUpdateStruct()
697 VarTree* ptr = 0;
698 if (!m_updateStruct.empty()) {
699 ptr = m_updateStruct.front();
700 m_updateStruct.pop_front();
702 return ptr;
706 void ExprWnd::editValue(VarTree* item, const QString& text)
708 if (m_edit == 0)
709 m_edit = new ValueEdit(this);
711 QRect r = visualItemRect(item);
712 int x = columnViewportPosition(1);
713 int y = r.y();
714 int w = columnWidth(1);
715 int h = r.height();
718 * Make the edit widget at least 5 characters wide (but not wider than
719 * this widget). If less than half of this widget is used to display
720 * the text, scroll this widget so that half of it shows the text (or
721 * less than half of it if the text is shorter).
723 QFontMetrics metr = m_edit->font();
724 int wMin = metr.width("88888");
725 if (w < wMin)
726 w = wMin;
727 int wThis = viewport()->width();
728 if (x >= wThis/2 && // less than half the width displays text
729 x+w > wThis) // not all text is visible
731 // scroll so that more text is visible
732 QScrollBar* pScrollBar = horizontalScrollBar();
733 int wScroll = QMIN(x-wThis/2, x+w-wThis);
734 pScrollBar->setValue(pScrollBar->value() + wScroll);
735 x -= wScroll;
737 else if (x < 0)
739 // don't let the edit move out at the left
740 x = 0;
743 // make the edit box as wide as the visible column
744 QRect rect(x,y, wThis-x,h);
745 m_edit->setText(text);
746 m_edit->selectAll();
748 m_edit->setGeometry(rect);
749 m_edit->m_finished = false;
750 m_edit->m_item = item;
751 m_edit->show();
752 m_edit->setFocus();
755 bool ExprWnd::isEditing() const
757 return m_edit != 0 && m_edit->isVisible();
761 ValueEdit::ValueEdit(ExprWnd* parent) :
762 QLineEdit(parent->viewport(), "valueedit")
764 setFrame(false);
765 hide();
766 lower(); // lower the window below scrollbars
767 connect(parent, SIGNAL(itemActivated(QTreeWidgetItem*,int)),
768 SLOT(slotSelectionChanged()));
769 connect(parent, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)),
770 SLOT(slotSelectionChanged()));
771 connect(parent, SIGNAL(itemExpanded(QTreeWidgetItem*)),
772 SLOT(slotSelectionChanged()));
773 connect(parent, SIGNAL(itemCollapsed(QTreeWidgetItem*)),
774 SLOT(slotSelectionChanged()));
775 connect(this, SIGNAL(done(VarTree*, const QString&)),
776 parent, SIGNAL(editValueCommitted(VarTree*, const QString&)));
779 ValueEdit::~ValueEdit()
783 void ValueEdit::terminate(bool commit)
785 TRACE(commit?"ValueEdit::terminate(true)":"ValueEdit::terminate(false)");
786 if (!m_finished)
788 m_finished = true;
789 hide(); // will call focusOutEvent, that's why we need m_finished
790 if (commit) {
791 emit done(m_item, text());
796 void ValueEdit::keyPressEvent(QKeyEvent *e)
798 if(e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter)
799 terminate(true);
800 else if(e->key() == Qt::Key_Escape)
801 terminate(false);
802 else
803 QLineEdit::keyPressEvent(e);
806 void ValueEdit::paintEvent(QPaintEvent* e)
808 QLineEdit::paintEvent(e);
810 QPainter p(this);
811 p.drawRect(rect());
814 void ValueEdit::focusOutEvent(QFocusEvent* ev)
816 TRACE("ValueEdit::focusOutEvent");
817 QFocusEvent* focusEv = static_cast<QFocusEvent*>(ev);
818 if (focusEv->reason() == Qt::ActiveWindowFocusReason)
820 // Switching to a different window should terminate the edit,
821 // because if the window with this variable display is floating
822 // then that different window could be the main window, where
823 // the user had clicked one of the Execute buttons. This in turn
824 // may pull the item away that we are editing here.
825 terminate(false);
827 // Don't let a RMB close the editor
828 else if (focusEv->reason() != Qt::PopupFocusReason)
830 terminate(true);
834 void ValueEdit::slotSelectionChanged()
836 TRACE("ValueEdit::slotSelectionChanged");
837 terminate(false);