Make the value edit window a pointer rather then a member object.
[kdbg.git] / kdbg / exprwnd.cpp
blobb6be0831be30b6fe04c234af7307df7af45edd55
1 // $Id$
3 // Copyright by Johannes Sixt
4 // This file is under GPL, the GNU General Public Licence
6 #include "exprwnd.h"
7 #include "exprwnd.moc"
8 #include "typetable.h"
9 #include <qstrlist.h>
10 #include <qpainter.h>
11 #include <qscrollbar.h>
12 #include <kapp.h>
13 #include <kiconloader.h> /* icons */
14 #ifdef HAVE_CONFIG_H
15 #include "config.h"
16 #endif
17 #include "mydebug.h"
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),
24 m_type(0),
25 m_exprIndex(0),
26 m_exprIndexUseGuard(false),
27 m_value(v->m_value)
29 setDelayedExpanding(m_varKind == VKpointer);
30 setExpanded(v->m_initiallyExpanded);
33 VarTree::VarTree(const QString& name) :
34 KTreeViewItem(name),
35 m_varKind(VKsimple),
36 m_nameKind(VarTree::NKplain),
37 m_valueChanged(false),
38 m_type(0),
39 m_exprIndex(0),
40 m_exprIndexUseGuard(false)
44 VarTree::~VarTree()
48 void VarTree::paintValue(QPainter* p)
50 p->save();
51 int cellHeight = height(p->fontMetrics());
52 int textX = 2;
53 int textY = (cellHeight - p->fontMetrics().height()) / 2 +
54 p->fontMetrics().ascent();
56 if (m_valueChanged) {
57 p->setPen(red);
59 // p->setBackgroundColor(cg.base());
60 p->drawText(textX, textY, value(), value().length());
61 p->restore();
64 int VarTree::valueWidth()
66 assert(owner != 0);
67 return owner->fontMetrics().width(value()) + 4;
70 QString VarTree::computeExpr() const
72 assert(getParent() != 0);
73 // just to be sure
74 if (getParent() == 0)
75 return QString();
77 // top-level items are special
78 if (getParent()->getParent() == 0)
79 return getText();
81 // get parent expr
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) {
87 return parentExpr;
89 /* augment by this item's text */
90 QString result;
91 /* if this is an address, dereference it */
92 if (m_nameKind == NKaddress) {
93 ASSERT(par->m_varKind == VKpointer);
94 result = "*" + parentExpr;
95 return result;
97 switch (par->m_varKind) {
98 case VKarray:
100 QString index = getText();
101 int i = 1;
102 // skip past the index
103 while (index[i].isDigit())
104 i++;
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;
115 break;
116 case VKstruct:
117 result = "(" + parentExpr + ")." + getText();
118 break;
119 case VKsimple: /* parent can't be simple */
120 case VKpointer: /* handled in NKaddress */
121 case VKdummy: /* can't occur at all */
122 ASSERT(false);
123 result = parentExpr; /* paranoia */
124 break;
126 return result;
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) {
138 c = c->getParent();
140 return c != 0;
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) {
149 setValue(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
156 * black).
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();
171 while (child != 0) {
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) {
178 if (isWcharT())
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);
186 return;
188 #ifndef I_know_a_way_to_do_this_cleanly
189 return;
190 #else
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 != '(')
195 return;
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 */
204 return;
206 const QString& typeName =
207 QString::fromLatin1(start+1, p-start-3) // minus 3 chars
208 .stripWhiteSpace();
209 m_type = typeTable.lookup(typeName);
210 if (m_type == 0) {
211 m_type = TypeInfo::unknownType();
213 #endif
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 */
222 if (m_type == 0) {
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.
233 if (m_type == 0) {
234 m_type = TypeInfo::unknownType();
236 } // else
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();
258 while (child != 0 &&
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())
265 // got a type!
266 return child->m_type;
268 child = child->nextSibling();
271 return 0;
274 ExprValue::ExprValue(const QString& name, VarTree::NameKind aKind) :
275 m_name(name),
276 m_varKind(VarTree::VKsimple),
277 m_nameKind(aKind),
278 m_child(0),
279 m_next(0),
280 m_initiallyExpanded(false)
284 ExprValue::~ExprValue()
286 delete m_child;
287 delete m_next;
290 void ExprValue::appendChild(ExprValue* newChild)
292 if (m_child == 0) {
293 m_child = newChild;
294 } else {
295 // walk chain of children to find the last one
296 ExprValue* last = m_child;
297 while (last->m_next != 0)
298 last = last->m_next;
299 last->m_next = newChild;
301 newChild->m_next = 0; // just to be sure
304 uint ExprValue::childCount() const
306 uint i = 0;
307 ExprValue* c = m_child;
308 while (c) {
309 ++i;
310 c = c->m_next;
312 return i;
317 ExprWnd::ExprWnd(QWidget* parent, const char* name) :
318 KTreeView(parent, name),
319 maxValueWidth(0),
320 m_edit(0)
322 setNumCols(2);
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");
332 ExprWnd::~ExprWnd()
336 void ExprWnd::exprList(QStrList& exprs)
338 // ASSERT(exprs does deep-copies)
339 VarTree* item;
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);
349 insertItem(display);
351 // replace it right away
352 updateExpr(display, expr, typeTable);
353 return display;
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();
362 if (item == 0) {
363 return;
365 // now update it
366 if (updateExprRec(item, expr, typeTable)) {
367 updateVisibleItems();
368 updateValuesWidth();
369 repaint();
371 collectUnknownTypes(item);
374 void ExprWnd::updateExpr(VarTree* display, ExprValue* newValues, ProgramTypeTable& typeTable)
376 if (updateExprRec(display, newValues, typeTable) &&
377 display->isVisible())
379 updateVisibleItems();
380 updateValuesWidth();
381 repaint();
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)))
423 if (isExpanded) {
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) {
454 if (isExpanded &&
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
462 * can stop here.
464 if (newValues->m_child == 0) {
465 return display->m_valueChanged;
469 ASSERT(display->childCount() == newValues->childCount());
471 // go for children
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) {
479 // set new name
480 vDisplay->setText(vNew->m_name);
481 int i = itemRow(vDisplay);
482 if (i >= 0) {
483 updateCell(i, 0, true);
484 childChanged = true;
487 // recurse
488 if (updateExprRec(vDisplay, vNew, typeTable)) {
489 childChanged = true;
491 vDisplay = vDisplay->nextSibling();
492 vNew = vNew->m_next;
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) {
506 return;
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
528 * is completed.
530 display->m_partialValue = formatWCharPointer(newValue->m_value);
532 else
533 display->m_partialValue = display->m_type->m_displayString[0];
534 m_updateStruct.append(display);
536 else
538 if (display->updateValue(newValue->m_value)) {
539 int i = itemRow(display);
540 if (i >= 0) {
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);
553 if (i >= 0) {
554 updateValuesWidth();
555 updateCell(i, 1, true);
558 // reset the value
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()) {
569 unhookSubtree(c);
570 display->removeChild(c);
571 delete 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);
578 // recurse
579 replaceChildren(vNew, v);
583 void ExprWnd::collectUnknownTypes(VarTree* var)
586 * forEveryItem does not scan the root item itself. So we must do it
587 * ourselves.
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);
599 else
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);
631 else
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);
644 return false;
647 QString ExprWnd::formatWCharPointer(QString value)
649 int pos = value.find(") ");
650 if (pos > 0)
651 value = value.mid(pos+2);
652 return value + " L";
656 VarTree* ExprWnd::topLevelExprByName(const char* name)
658 VarTree* item = firstChild();
659 while (item != 0 && item->getText() != name)
660 item = item->nextSibling();
662 return item;
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)
669 return 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();
683 if (item != 0)
684 return item;
686 // try in base classes
687 item = v->firstChild();
688 while (item != 0 &&
689 item->m_nameKind == VarTree::NKtype)
691 v = memberByName(item, name);
692 if (v != 0)
693 return v;
694 item = item->nextSibling();
696 return 0;
699 void ExprWnd::removeExpr(VarTree* item)
701 unhookSubtree(item);
703 takeItem(item);
704 delete item;
706 updateValuesWidth();
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)
720 if (subTree == 0)
721 return;
723 VarTree* checkItem = list.first();
724 while (checkItem != 0) {
725 if (!subTree->isAncestorEq(checkItem)) {
726 // checkItem is not an item from subTree
727 // advance
728 checkItem = list.next();
729 } else {
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
737 list.remove();
738 /* we deleted the last element, so we've finished */
739 checkItem = 0;
740 } else {
741 list.remove();
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();
759 if (ptr != 0) {
760 m_updatePtrs.remove();
762 return ptr;
765 VarTree* ExprWnd::nextUpdateType()
767 VarTree* ptr = m_updateType.first();
768 if (ptr != 0) {
769 m_updateType.remove();
771 return ptr;
774 VarTree* ExprWnd::nextUpdateStruct()
776 VarTree* ptr = m_updateStruct.first();
777 if (ptr != 0) {
778 m_updateStruct.remove();
780 return ptr;
783 void ExprWnd::paintCell(QPainter* painter, int row, int col)
785 if (col == 0) {
786 KTreeView::paintCell(painter, row, col);
787 } else {
788 VarTree* item = static_cast<VarTree*>(itemAt(row));
789 if (item != 0) {
790 item->paintValue(painter);
795 int ExprWnd::cellWidth(int col) const
797 if (col == 0) {
798 return KTreeView::cellWidth(col);
799 } else {
800 return maxValueWidth;
804 void ExprWnd::updateValuesWidth()
806 int maxW = 0;
807 forEveryVisibleItem(static_cast<KForEveryFunc>(&getMaxValueWidth), &maxW);
808 maxValueWidth = maxW;
809 updateTableSize();
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();
818 if(w > *maxW)
819 *maxW = w;
820 return false;
823 void ExprWnd::slotExpandOrCollapse(int)
825 updateValuesWidth();
828 void ExprWnd::editValue(int row, const QString& text)
830 if (m_edit == 0)
831 m_edit = new ValueEdit(this);
833 int x;
834 colXPos(1, &x);
835 int y;
836 rowYPos(row, &y);
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");
849 if (w < wMin)
850 w = wMin;
851 int wThis = width();
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);
860 colXPos(1, &x);
862 else if (x < 0)
864 // don't let the edit move out at the left
865 x = 0;
868 // make the edit box as wide as the visible column
869 QRect rect(x,y, wThis-x,h);
870 m_edit->setText(text);
871 m_edit->selectAll();
873 m_edit->setGeometry(rect);
874 m_edit->m_finished = false;
875 m_edit->m_row = row;
876 m_edit->show();
877 m_edit->setFocus();
880 bool ExprWnd::isEditing() const
882 return m_edit != 0 && m_edit->isVisible();
886 ValueEdit::ValueEdit(ExprWnd* parent) :
887 QLineEdit(parent, "valueedit")
889 setFrame(false);
890 hide();
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)");
906 if (!m_finished)
908 m_finished = true;
909 hide(); // will call focusOutEvent, that's why we need m_finished
910 if (commit) {
911 emit done(m_row, text());
916 void ValueEdit::keyPressEvent(QKeyEvent *e)
918 if(e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter)
919 terminate(true);
920 else if(e->key() == Qt::Key_Escape)
921 terminate(false);
922 else
923 QLineEdit::keyPressEvent(e);
926 void ValueEdit::paintEvent(QPaintEvent* e)
928 QLineEdit::paintEvent(e);
930 QPainter p(this);
931 p.drawRect(rect());
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)
942 terminate(true);
946 void ValueEdit::slotSelectionChanged()
948 TRACE("ValueEdit::slotSelectionChanged");
949 terminate(false);