2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2011-2016, Rene Gollent, rene@gollent.com.
4 * Distributed under the terms of the MIT License.
8 #include "VariablesView.h"
15 #include <Clipboard.h>
17 #include <PopUpMenu.h>
20 #include <AutoDeleter.h>
21 #include <AutoLocker.h>
22 #include <PromptWindow.h>
24 #include "table/TableColumns.h"
26 #include "ActionMenuItem.h"
27 #include "AppMessageCodes.h"
28 #include "Architecture.h"
29 #include "ExpressionInfo.h"
30 #include "ExpressionValues.h"
31 #include "FileSourceCode.h"
33 #include "FunctionID.h"
34 #include "FunctionInstance.h"
35 #include "GuiSettingsUtils.h"
36 #include "MessageCodes.h"
37 #include "RangeList.h"
39 #include "SettingsMenu.h"
40 #include "SourceLanguage.h"
41 #include "StackTrace.h"
42 #include "StackFrame.h"
43 #include "StackFrameValues.h"
44 #include "StringUtils.h"
45 #include "StringValue.h"
46 #include "SyntheticPrimitiveType.h"
47 #include "TableCellValueEditor.h"
48 #include "TableCellValueRenderer.h"
50 #include "TeamDebugInfo.h"
53 #include "TypeComponentPath.h"
54 #include "TypeHandlerRoster.h"
55 #include "TypeLookupConstraints.h"
58 #include "ValueHandler.h"
59 #include "ValueHandlerRoster.h"
60 #include "ValueLocation.h"
61 #include "ValueNode.h"
62 #include "ValueNodeManager.h"
64 #include "VariableEditWindow.h"
65 #include "VariableValueNodeChild.h"
66 #include "VariablesViewState.h"
67 #include "VariablesViewStateHistory.h"
71 VALUE_NODE_TYPE
= 'valn'
76 MSG_MODEL_NODE_HIDDEN
= 'monh',
77 MSG_VALUE_NODE_NEEDS_VALUE
= 'mvnv',
78 MSG_RESTORE_PARTIAL_VIEW_STATE
= 'mpvs',
79 MSG_ADD_WATCH_EXPRESSION
= 'awex',
80 MSG_REMOVE_WATCH_EXPRESSION
= 'rwex'
84 // maximum number of array elements to show by default
85 static const uint64 kMaxArrayElementCount
= 10;
88 // #pragma mark - FunctionKey
91 struct VariablesView::FunctionKey
{
94 FunctionKey(FunctionID
* function
)
100 uint32
HashValue() const
102 return function
->HashValue();
105 bool operator==(const FunctionKey
& other
) const
107 return *function
== *other
.function
;
112 // #pragma mark - ExpressionInfoEntry
115 struct VariablesView::ExpressionInfoEntry
: FunctionKey
, ExpressionInfoList
{
116 ExpressionInfoEntry
* next
;
118 ExpressionInfoEntry(FunctionID
* function
)
120 FunctionKey(function
),
121 ExpressionInfoList(10, false)
123 function
->AcquireReference();
126 ~ExpressionInfoEntry()
131 void SetInfo(const ExpressionInfoList
& infoList
)
135 for (int32 i
= 0; i
< infoList
.CountItems(); i
++) {
136 ExpressionInfo
* info
= infoList
.ItemAt(i
);
140 info
->AcquireReference();
147 for (int32 i
= 0; i
< CountItems(); i
++)
148 ItemAt(i
)->ReleaseReference();
155 // #pragma mark - ExpressionInfoEntryHashDefinition
158 struct VariablesView::ExpressionInfoEntryHashDefinition
{
159 typedef FunctionKey KeyType
;
160 typedef ExpressionInfoEntry ValueType
;
162 size_t HashKey(const FunctionKey
& key
) const
164 return key
.HashValue();
167 size_t Hash(const ExpressionInfoEntry
* value
) const
169 return value
->HashValue();
172 bool Compare(const FunctionKey
& key
,
173 const ExpressionInfoEntry
* value
) const
175 return key
== *value
;
178 ExpressionInfoEntry
*& GetLink(ExpressionInfoEntry
* value
) const
185 // #pragma mark - ContainerListener
188 class VariablesView::ContainerListener
: public ValueNodeContainer::Listener
{
190 ContainerListener(BHandler
* indirectTarget
);
192 void SetModel(VariableTableModel
* model
);
194 virtual void ValueNodeChanged(ValueNodeChild
* nodeChild
,
195 ValueNode
* oldNode
, ValueNode
* newNode
);
196 virtual void ValueNodeChildrenCreated(ValueNode
* node
);
197 virtual void ValueNodeChildrenDeleted(ValueNode
* node
);
198 virtual void ValueNodeValueChanged(ValueNode
* node
);
200 virtual void ModelNodeHidden(ModelNode
* node
);
202 virtual void ModelNodeValueRequested(ModelNode
* node
);
204 virtual void ModelNodeRestoreViewStateRequested(ModelNode
* node
);
207 BHandler
* fIndirectTarget
;
208 VariableTableModel
* fModel
;
212 // #pragma mark - ExpressionVariableID
215 class VariablesView::ExpressionVariableID
: public ObjectID
{
217 ExpressionVariableID(ExpressionInfo
* info
)
221 fInfo
->AcquireReference();
224 virtual ~ExpressionVariableID()
226 fInfo
->ReleaseReference();
229 virtual bool operator==(const ObjectID
& other
) const
231 const ExpressionVariableID
* otherID
232 = dynamic_cast<const ExpressionVariableID
*>(&other
);
236 return fInfo
== otherID
->fInfo
;
240 virtual uint32
ComputeHashValue() const
242 uint32 hash
= *(uint32
*)(&fInfo
);
243 hash
= hash
* 19 + StringUtils::HashValue(fInfo
->Expression());
249 ExpressionInfo
* fInfo
;
253 // #pragma mark - ModelNode
256 class VariablesView::ModelNode
: public BReferenceable
{
258 ModelNode(ModelNode
* parent
, Variable
* variable
, ValueNodeChild
* nodeChild
,
259 bool isPresentationNode
)
262 fNodeChild(nodeChild
),
267 fTableCellRenderer(NULL
),
268 fLastRendererSettings(),
270 fComponentPath(NULL
),
271 fIsPresentationNode(isPresentationNode
),
273 fValueChanged(false),
276 fVariable
->AcquireReference();
277 fNodeChild
->AcquireReference();
282 SetTableCellRenderer(NULL
);
283 SetValueHandler(NULL
);
286 for (int32 i
= 0; ModelNode
* child
= fChildren
.ItemAt(i
); i
++)
287 child
->ReleaseReference();
289 fNodeChild
->ReleaseReference();
290 fVariable
->ReleaseReference();
292 if (fComponentPath
!= NULL
)
293 fComponentPath
->ReleaseReference();
295 if (fCastedType
!= NULL
)
296 fCastedType
->ReleaseReference();
301 fComponentPath
= new(std::nothrow
) TypeComponentPath();
302 if (fComponentPath
== NULL
)
306 *fComponentPath
= *fParent
->GetPath();
308 TypeComponent component
;
309 // TODO: this should actually discriminate between different
310 // classes of type component kinds
311 component
.SetToBaseType(fNodeChild
->GetType()->Kind(),
312 0, fNodeChild
->Name());
314 fComponentPath
->AddComponent(component
);
319 ModelNode
* Parent() const
324 ValueNodeChild
* NodeChild() const
329 const BString
& Name() const
331 return fPresentationName
.IsEmpty()
332 ? fNodeChild
->Name() : fPresentationName
;
335 void SetPresentationName(const BString
& name
)
337 fPresentationName
= name
;
340 Type
* GetType() const
342 if (fCastedType
!= NULL
)
345 return fNodeChild
->GetType();
348 Variable
* GetVariable() const
353 Value
* GetValue() const
358 void SetValue(Value
* value
)
364 fValue
->ReleaseReference();
369 fValue
->AcquireReference();
374 const BVariant
& PreviousValue() const
376 return fPreviousValue
;
379 void SetPreviousValue(const BVariant
& value
)
381 fPreviousValue
= value
;
384 Type
* GetCastedType() const
389 void SetCastedType(Type
* type
)
391 if (fCastedType
!= NULL
)
392 fCastedType
->ReleaseReference();
396 fCastedType
->AcquireReference();
399 const BMessage
& GetLastRendererSettings() const
401 return fLastRendererSettings
;
404 void SetLastRendererSettings(const BMessage
& settings
)
406 fLastRendererSettings
= settings
;
409 TypeComponentPath
* GetPath() const
411 return fComponentPath
;
414 ValueHandler
* GetValueHandler() const
416 return fValueHandler
;
419 void SetValueHandler(ValueHandler
* handler
)
421 if (handler
== fValueHandler
)
424 if (fValueHandler
!= NULL
)
425 fValueHandler
->ReleaseReference();
427 fValueHandler
= handler
;
429 if (fValueHandler
!= NULL
)
430 fValueHandler
->AcquireReference();
434 TableCellValueRenderer
* TableCellRenderer() const
436 return fTableCellRenderer
;
439 void SetTableCellRenderer(TableCellValueRenderer
* renderer
)
441 if (renderer
== fTableCellRenderer
)
444 if (fTableCellRenderer
!= NULL
)
445 fTableCellRenderer
->ReleaseReference();
447 fTableCellRenderer
= renderer
;
449 if (fTableCellRenderer
!= NULL
)
450 fTableCellRenderer
->AcquireReference();
453 bool IsPresentationNode() const
455 return fIsPresentationNode
;
458 bool IsHidden() const
463 void SetHidden(bool hidden
)
468 bool ValueChanged() const
470 return fValueChanged
;
473 int32
CountChildren() const
475 return fChildren
.CountItems();
478 ModelNode
* ChildAt(int32 index
) const
480 return fChildren
.ItemAt(index
);
483 int32
IndexOf(ModelNode
* child
) const
485 return fChildren
.IndexOf(child
);
488 bool AddChild(ModelNode
* child
)
490 if (!fChildren
.AddItem(child
))
493 child
->AcquireReference();
497 bool RemoveChild(ModelNode
* child
)
499 if (!fChildren
.RemoveItem(child
))
502 child
->ReleaseReference();
506 bool RemoveAllChildren()
508 for (int32 i
= 0; i
< fChildren
.CountItems(); i
++)
509 RemoveChild(fChildren
.ItemAt(i
));
515 typedef BObjectList
<ModelNode
> ChildList
;
518 void _CompareValues()
520 fValueChanged
= false;
521 if (fValue
!= NULL
) {
522 if (fPreviousValue
.Type() != 0) {
524 fValue
->ToVariant(newValue
);
525 fValueChanged
= (fPreviousValue
!= newValue
);
527 // for expression variables, always consider the initial
528 // value as changed, since their evaluation has just been
529 // requested, and thus their initial value is by definition
531 fValueChanged
= dynamic_cast<ExpressionVariableID
*>(
532 fVariable
->ID()) != NULL
;
539 ValueNodeChild
* fNodeChild
;
542 BVariant fPreviousValue
;
543 ValueHandler
* fValueHandler
;
544 TableCellValueRenderer
* fTableCellRenderer
;
545 BMessage fLastRendererSettings
;
548 TypeComponentPath
* fComponentPath
;
549 bool fIsPresentationNode
;
552 BString fPresentationName
;
559 // #pragma mark - VariablesExpressionInfo
562 class VariablesView::VariablesExpressionInfo
: public ExpressionInfo
{
564 VariablesExpressionInfo(const BString
& expression
, ModelNode
* node
)
566 ExpressionInfo(expression
),
569 fTargetNode
->AcquireReference();
572 virtual ~VariablesExpressionInfo()
574 fTargetNode
->ReleaseReference();
577 inline ModelNode
* TargetNode() const
583 ModelNode
* fTargetNode
;
587 // #pragma mark - VariableValueColumn
590 class VariablesView::VariableValueColumn
: public StringTableColumn
{
592 VariableValueColumn(int32 modelIndex
, const char* title
, float width
,
593 float minWidth
, float maxWidth
, uint32 truncate
= B_TRUNCATE_MIDDLE
,
594 alignment align
= B_ALIGN_RIGHT
)
596 StringTableColumn(modelIndex
, title
, width
, minWidth
, maxWidth
,
602 void DrawValue(const BVariant
& value
, BRect rect
, BView
* targetView
)
604 // draw the node's value with the designated renderer
605 if (value
.Type() == VALUE_NODE_TYPE
) {
606 ModelNode
* node
= dynamic_cast<ModelNode
*>(value
.ToReferenceable());
607 if (node
!= NULL
&& node
->GetValue() != NULL
608 && node
->TableCellRenderer() != NULL
) {
609 node
->TableCellRenderer()->RenderValue(node
->GetValue(),
610 node
->ValueChanged(), rect
, targetView
);
613 } else if (value
.Type() == B_STRING_TYPE
) {
614 fField
.SetString(value
.ToString());
616 // fall back to drawing an empty string
617 fField
.SetString("");
619 fField
.SetWidth(Width());
620 fColumn
.DrawField(&fField
, rect
, targetView
);
623 float GetPreferredWidth(const BVariant
& value
, BView
* targetView
) const
625 // get the preferred width from the node's designated renderer
626 if (value
.Type() == VALUE_NODE_TYPE
) {
627 ModelNode
* node
= dynamic_cast<ModelNode
*>(value
.ToReferenceable());
628 if (node
!= NULL
&& node
->GetValue() != NULL
629 && node
->TableCellRenderer() != NULL
) {
630 return node
->TableCellRenderer()->PreferredValueWidth(
631 node
->GetValue(), targetView
);
635 return fColumn
.BTitledColumn::GetPreferredWidth(NULL
, targetView
);
638 virtual BField
* PrepareField(const BVariant
& _value
) const
645 // #pragma mark - VariableTableModel
648 class VariablesView::VariableTableModel
: public TreeTableModel
,
649 public TreeTableToolTipProvider
{
651 VariableTableModel(ValueNodeManager
* manager
);
652 ~VariableTableModel();
656 void SetContainerListener(
657 ContainerListener
* listener
);
659 void SetStackFrame(::Thread
* thread
,
660 StackFrame
* stackFrame
);
662 void ValueNodeChanged(ValueNodeChild
* nodeChild
,
663 ValueNode
* oldNode
, ValueNode
* newNode
);
664 void ValueNodeChildrenCreated(ValueNode
* node
);
665 void ValueNodeChildrenDeleted(ValueNode
* node
);
666 void ValueNodeValueChanged(ValueNode
* node
);
668 virtual int32
CountColumns() const;
669 virtual void* Root() const;
670 virtual int32
CountChildren(void* parent
) const;
671 virtual void* ChildAt(void* parent
, int32 index
) const;
672 virtual bool GetValueAt(void* object
, int32 columnIndex
,
675 bool GetTreePath(ModelNode
* node
,
676 TreeTablePath
& _path
) const;
678 void NodeExpanded(ModelNode
* node
);
680 void NotifyNodeChanged(ModelNode
* node
);
681 void NotifyNodeHidden(ModelNode
* node
);
683 virtual bool GetToolTipForTablePath(
684 const TreeTablePath
& path
,
685 int32 columnIndex
, BToolTip
** _tip
);
687 status_t
AddSyntheticNode(Variable
* variable
,
688 ValueNodeChild
*& _child
,
689 const char* presentationName
= NULL
);
690 void RemoveSyntheticNode(ModelNode
* node
);
693 struct NodeHashDefinition
{
694 typedef ValueNodeChild
* KeyType
;
695 typedef ModelNode ValueType
;
697 size_t HashKey(const ValueNodeChild
* key
) const
702 size_t Hash(const ModelNode
* value
) const
704 return HashKey(value
->NodeChild());
707 bool Compare(const ValueNodeChild
* key
,
708 const ModelNode
* value
) const
710 return value
->NodeChild() == key
;
713 ModelNode
*& GetLink(ModelNode
* value
) const
719 typedef BObjectList
<ModelNode
> NodeList
;
720 typedef BOpenHashTable
<NodeHashDefinition
> NodeTable
;
723 // container must be locked
725 status_t
_AddNode(Variable
* variable
, ModelNode
* parent
,
726 ValueNodeChild
* nodeChild
,
727 bool isPresentationNode
= false,
728 bool isOnlyChild
= false);
732 ValueNodeManager
* fNodeManager
;
733 ContainerListener
* fContainerListener
;
735 NodeTable fNodeTable
;
739 class VariablesView::ContextMenu
: public BPopUpMenu
{
741 ContextMenu(const BMessenger
& parent
, const char* name
)
742 : BPopUpMenu(name
, false, false),
751 BMessage
message(MSG_VARIABLES_VIEW_CONTEXT_MENU_DONE
);
752 message
.AddPointer("menu", this);
753 fParent
.SendMessage(&message
);
761 // #pragma mark - TableCellContextMenuTracker
764 class VariablesView::TableCellContextMenuTracker
: public BReferenceable
,
767 TableCellContextMenuTracker(ModelNode
* node
, BLooper
* parentLooper
,
768 const BMessenger
& parent
)
771 fParentLooper(parentLooper
),
773 fRendererSettings(NULL
),
774 fRendererSettingsMenu(NULL
),
775 fRendererMenuAdded(false),
776 fMenuPreparedToShow(false)
778 fNode
->AcquireReference();
781 ~TableCellContextMenuTracker()
785 if (fRendererSettingsMenu
!= NULL
)
786 fRendererSettingsMenu
->ReleaseReference();
788 if (fRendererSettings
!= NULL
)
789 fRendererSettings
->ReleaseReference();
791 fNode
->ReleaseReference();
794 status_t
Init(Settings
* rendererSettings
,
795 SettingsMenu
* rendererSettingsMenu
,
796 ContextActionList
* preSettingsActions
= NULL
,
797 ContextActionList
* postSettingsActions
= NULL
)
799 if (rendererSettings
== NULL
&& preSettingsActions
== NULL
800 && postSettingsActions
== NULL
) {
804 if (rendererSettings
!= NULL
) {
805 fRendererSettings
= rendererSettings
;
806 fRendererSettings
->AcquireReference();
809 fRendererSettingsMenu
= rendererSettingsMenu
;
810 fRendererSettingsMenu
->AcquireReference();
813 fContextMenu
= new(std::nothrow
) ContextMenu(fParent
,
814 "table cell settings popup");
815 if (fContextMenu
== NULL
)
818 status_t error
= B_OK
;
819 if (preSettingsActions
!= NULL
820 && preSettingsActions
->CountItems() > 0) {
821 error
= _AddActionItems(preSettingsActions
);
825 if (fRendererSettingsMenu
!= NULL
|| postSettingsActions
!= NULL
)
826 fContextMenu
->AddSeparatorItem();
829 if (fRendererSettingsMenu
!= NULL
) {
830 error
= fRendererSettingsMenu
->AddToMenu(fContextMenu
,
831 fContextMenu
->CountItems());
835 if (postSettingsActions
!= NULL
)
836 fContextMenu
->AddSeparatorItem();
839 if (postSettingsActions
!= NULL
) {
840 error
= _AddActionItems(postSettingsActions
);
846 if (fRendererSettings
!= NULL
) {
847 AutoLocker
<Settings
> settingsLocker(fRendererSettings
);
848 fRendererSettings
->AddListener(this);
849 fRendererMenuAdded
= true;
855 void ShowMenu(BPoint screenWhere
)
857 if (fRendererMenuAdded
)
858 fRendererSettingsMenu
->PrepareToShow(fParentLooper
);
860 for (int32 i
= 0; i
< fContextMenu
->CountItems(); i
++) {
861 ActionMenuItem
* item
= dynamic_cast<ActionMenuItem
*>(
862 fContextMenu
->ItemAt(i
));
864 item
->PrepareToShow(fParentLooper
, fParent
.Target(NULL
));
867 fMenuPreparedToShow
= true;
869 BRect
mouseRect(screenWhere
, screenWhere
);
870 mouseRect
.InsetBy(-4.0, -4.0);
871 fContextMenu
->Go(screenWhere
, true, false, mouseRect
, true);
874 bool FinishMenu(bool force
)
876 bool stillActive
= false;
878 if (fMenuPreparedToShow
) {
879 if (fRendererMenuAdded
)
880 stillActive
= fRendererSettingsMenu
->Finish(fParentLooper
,
882 for (int32 i
= 0; i
< fContextMenu
->CountItems(); i
++) {
883 ActionMenuItem
* item
= dynamic_cast<ActionMenuItem
*>(
884 fContextMenu
->ItemAt(i
));
886 stillActive
|= item
->Finish(fParentLooper
,
887 fParent
.Target(NULL
), force
);
891 fMenuPreparedToShow
= stillActive
;
894 if (fRendererMenuAdded
) {
895 fRendererSettingsMenu
->RemoveFromMenu();
896 fRendererSettings
->RemoveListener(this);
897 fRendererMenuAdded
= false;
900 if (fContextMenu
!= NULL
) {
909 // Settings::Listener
911 virtual void SettingValueChanged(Setting
* setting
)
913 BMessage
message(MSG_VARIABLES_VIEW_NODE_SETTINGS_CHANGED
);
914 fNode
->AcquireReference();
915 if (message
.AddPointer("node", fNode
) != B_OK
916 || fParent
.SendMessage(&message
) != B_OK
) {
917 fNode
->ReleaseReference();
921 status_t
_AddActionItems(ContextActionList
* actions
)
923 if (fContextMenu
== NULL
)
926 int32 index
= fContextMenu
->CountItems();
927 for (int32 i
= 0; ActionMenuItem
* item
= actions
->ItemAt(i
); i
++) {
928 if (!fContextMenu
->AddItem(item
, index
+ i
)) {
929 for (i
--; i
>= 0; i
--)
930 fContextMenu
->RemoveItem(fContextMenu
->ItemAt(index
+ i
));
941 BLooper
* fParentLooper
;
943 ContextMenu
* fContextMenu
;
944 Settings
* fRendererSettings
;
945 SettingsMenu
* fRendererSettingsMenu
;
946 bool fRendererMenuAdded
;
947 bool fMenuPreparedToShow
;
951 // #pragma mark - ContainerListener
954 VariablesView::ContainerListener::ContainerListener(BHandler
* indirectTarget
)
956 fIndirectTarget(indirectTarget
),
963 VariablesView::ContainerListener::SetModel(VariableTableModel
* model
)
970 VariablesView::ContainerListener::ValueNodeChanged(ValueNodeChild
* nodeChild
,
971 ValueNode
* oldNode
, ValueNode
* newNode
)
973 // If the looper is already locked, invoke the model's hook synchronously.
974 if (fIndirectTarget
->Looper()->IsLocked()) {
975 fModel
->ValueNodeChanged(nodeChild
, oldNode
, newNode
);
979 // looper not locked yet -- call asynchronously to avoid reverse locking
981 BReference
<ValueNodeChild
> nodeChildReference(nodeChild
);
982 BReference
<ValueNode
> oldNodeReference(oldNode
);
983 BReference
<ValueNode
> newNodeReference(newNode
);
985 BMessage
message(MSG_VALUE_NODE_CHANGED
);
986 if (message
.AddPointer("nodeChild", nodeChild
) == B_OK
987 && message
.AddPointer("oldNode", oldNode
) == B_OK
988 && message
.AddPointer("newNode", newNode
) == B_OK
989 && fIndirectTarget
->Looper()->PostMessage(&message
, fIndirectTarget
)
991 nodeChildReference
.Detach();
992 oldNodeReference
.Detach();
993 newNodeReference
.Detach();
999 VariablesView::ContainerListener::ValueNodeChildrenCreated(ValueNode
* node
)
1001 // If the looper is already locked, invoke the model's hook synchronously.
1002 if (fIndirectTarget
->Looper()->IsLocked()) {
1003 fModel
->ValueNodeChildrenCreated(node
);
1007 // looper not locked yet -- call asynchronously to avoid reverse locking
1009 BReference
<ValueNode
> nodeReference(node
);
1011 BMessage
message(MSG_VALUE_NODE_CHILDREN_CREATED
);
1012 if (message
.AddPointer("node", node
) == B_OK
1013 && fIndirectTarget
->Looper()->PostMessage(&message
, fIndirectTarget
)
1015 nodeReference
.Detach();
1021 VariablesView::ContainerListener::ValueNodeChildrenDeleted(ValueNode
* node
)
1023 // If the looper is already locked, invoke the model's hook synchronously.
1024 if (fIndirectTarget
->Looper()->IsLocked()) {
1025 fModel
->ValueNodeChildrenDeleted(node
);
1029 // looper not locked yet -- call asynchronously to avoid reverse locking
1031 BReference
<ValueNode
> nodeReference(node
);
1033 BMessage
message(MSG_VALUE_NODE_CHILDREN_DELETED
);
1034 if (message
.AddPointer("node", node
) == B_OK
1035 && fIndirectTarget
->Looper()->PostMessage(&message
, fIndirectTarget
)
1037 nodeReference
.Detach();
1043 VariablesView::ContainerListener::ValueNodeValueChanged(ValueNode
* node
)
1045 // If the looper is already locked, invoke the model's hook synchronously.
1046 if (fIndirectTarget
->Looper()->IsLocked()) {
1047 fModel
->ValueNodeValueChanged(node
);
1051 // looper not locked yet -- call asynchronously to avoid reverse locking
1053 BReference
<ValueNode
> nodeReference(node
);
1055 BMessage
message(MSG_VALUE_NODE_VALUE_CHANGED
);
1056 if (message
.AddPointer("node", node
) == B_OK
1057 && fIndirectTarget
->Looper()->PostMessage(&message
, fIndirectTarget
)
1059 nodeReference
.Detach();
1065 VariablesView::ContainerListener::ModelNodeHidden(ModelNode
* node
)
1067 BReference
<ModelNode
> nodeReference(node
);
1069 BMessage
message(MSG_MODEL_NODE_HIDDEN
);
1070 if (message
.AddPointer("node", node
) == B_OK
1071 && fIndirectTarget
->Looper()->PostMessage(&message
, fIndirectTarget
)
1073 nodeReference
.Detach();
1079 VariablesView::ContainerListener::ModelNodeValueRequested(ModelNode
* node
)
1081 BReference
<ModelNode
> nodeReference(node
);
1083 BMessage
message(MSG_VALUE_NODE_NEEDS_VALUE
);
1084 if (message
.AddPointer("node", node
) == B_OK
1085 && fIndirectTarget
->Looper()->PostMessage(&message
, fIndirectTarget
)
1087 nodeReference
.Detach();
1093 VariablesView::ContainerListener::ModelNodeRestoreViewStateRequested(
1096 BReference
<ModelNode
> nodeReference(node
);
1098 BMessage
message(MSG_RESTORE_PARTIAL_VIEW_STATE
);
1099 if (message
.AddPointer("node", node
) == B_OK
1100 && fIndirectTarget
->Looper()->PostMessage(&message
, fIndirectTarget
)
1102 nodeReference
.Detach();
1107 // #pragma mark - VariableTableModel
1110 VariablesView::VariableTableModel::VariableTableModel(
1111 ValueNodeManager
* manager
)
1114 fNodeManager(manager
),
1115 fContainerListener(NULL
),
1118 fNodeManager
->AcquireReference();
1122 VariablesView::VariableTableModel::~VariableTableModel()
1124 fNodeManager
->ReleaseReference();
1129 VariablesView::VariableTableModel::Init()
1131 return fNodeTable
.Init();
1136 VariablesView::VariableTableModel::SetContainerListener(
1137 ContainerListener
* listener
)
1139 if (listener
== fContainerListener
)
1142 if (fContainerListener
!= NULL
) {
1143 if (fNodeManager
!= NULL
)
1144 fNodeManager
->RemoveListener(fContainerListener
);
1146 fContainerListener
->SetModel(NULL
);
1149 fContainerListener
= listener
;
1151 if (fContainerListener
!= NULL
) {
1152 fContainerListener
->SetModel(this);
1154 if (fNodeManager
!= NULL
)
1155 fNodeManager
->AddListener(fContainerListener
);
1161 VariablesView::VariableTableModel::SetStackFrame(::Thread
* thread
,
1162 StackFrame
* stackFrame
)
1166 fNodeManager
->SetStackFrame(thread
, stackFrame
);
1168 int32 count
= fNodes
.CountItems();
1169 fNodeTable
.Clear(true);
1171 if (!fNodes
.IsEmpty()) {
1172 for (int32 i
= 0; i
< count
; i
++)
1173 fNodes
.ItemAt(i
)->ReleaseReference();
1177 NotifyNodesRemoved(TreeTablePath(), 0, count
);
1179 if (stackFrame
== NULL
)
1182 ValueNodeContainer
* container
= fNodeManager
->GetContainer();
1183 AutoLocker
<ValueNodeContainer
> containerLocker(container
);
1185 for (int32 i
= 0; i
< container
->CountChildren(); i
++) {
1186 VariableValueNodeChild
* child
= dynamic_cast<VariableValueNodeChild
*>(
1187 container
->ChildAt(i
));
1188 _AddNode(child
->GetVariable(), NULL
, child
);
1189 // top level nodes get their children added immediately
1190 // so those won't invoke our callback hook. Add them directly here.
1191 ValueNodeChildrenCreated(child
->Node());
1197 VariablesView::VariableTableModel::ValueNodeChanged(ValueNodeChild
* nodeChild
,
1198 ValueNode
* oldNode
, ValueNode
* newNode
)
1200 AutoLocker
<ValueNodeContainer
> containerLocker(
1201 fNodeManager
->GetContainer());
1202 ModelNode
* modelNode
= fNodeTable
.Lookup(nodeChild
);
1203 if (modelNode
== NULL
)
1206 if (oldNode
!= NULL
) {
1207 ValueNodeChildrenDeleted(oldNode
);
1208 NotifyNodeChanged(modelNode
);
1214 VariablesView::VariableTableModel::ValueNodeChildrenCreated(
1215 ValueNode
* valueNode
)
1217 AutoLocker
<ValueNodeContainer
> containerLocker(
1218 fNodeManager
->GetContainer());
1220 // check whether we know the node
1221 ValueNodeChild
* nodeChild
= valueNode
->NodeChild();
1222 if (nodeChild
== NULL
)
1225 ModelNode
* modelNode
= fNodeTable
.Lookup(nodeChild
);
1226 if (modelNode
== NULL
)
1229 // Iterate through the children and create model nodes for the ones we
1231 int32 childCount
= valueNode
->CountChildren();
1232 for (int32 i
= 0; i
< childCount
; i
++) {
1233 ValueNodeChild
* child
= valueNode
->ChildAt(i
);
1234 if (fNodeTable
.Lookup(child
) == NULL
) {
1235 _AddNode(modelNode
->GetVariable(), modelNode
, child
,
1236 child
->IsInternal(), childCount
== 1);
1239 ModelNode
* childNode
= fNodeTable
.Lookup(child
);
1240 if (childNode
!= NULL
)
1241 fContainerListener
->ModelNodeValueRequested(childNode
);
1244 if (valueNode
->ChildCreationNeedsValue())
1245 fContainerListener
->ModelNodeRestoreViewStateRequested(modelNode
);
1250 VariablesView::VariableTableModel::ValueNodeChildrenDeleted(ValueNode
* node
)
1252 AutoLocker
<ValueNodeContainer
> containerLocker(
1253 fNodeManager
->GetContainer());
1255 // check whether we know the node
1256 ValueNodeChild
* nodeChild
= node
->NodeChild();
1257 if (nodeChild
== NULL
)
1260 ModelNode
* modelNode
= fNodeTable
.Lookup(nodeChild
);
1261 if (modelNode
== NULL
)
1264 // in the case of an address node with a hidden child,
1265 // we want to send removal notifications for the children
1267 BReference
<ModelNode
> hiddenChild
;
1268 if (modelNode
->CountChildren() == 1
1269 && modelNode
->ChildAt(0)->IsHidden()) {
1270 hiddenChild
.SetTo(modelNode
->ChildAt(0));
1271 modelNode
->RemoveChild(hiddenChild
);
1272 modelNode
= hiddenChild
;
1273 fNodeTable
.Remove(hiddenChild
);
1276 for (int32 i
= modelNode
->CountChildren() - 1; i
>= 0 ; i
--) {
1277 BReference
<ModelNode
> childNode
= modelNode
->ChildAt(i
);
1278 // recursively remove the current node's child hierarchy.
1279 if (childNode
->CountChildren() != 0)
1280 ValueNodeChildrenDeleted(childNode
->NodeChild()->Node());
1282 TreeTablePath treePath
;
1283 if (GetTreePath(childNode
, treePath
)) {
1284 int32 index
= treePath
.RemoveLastComponent();
1285 NotifyNodesRemoved(treePath
, index
, 1);
1287 modelNode
->RemoveChild(childNode
);
1288 fNodeTable
.Remove(childNode
);
1294 VariablesView::VariableTableModel::ValueNodeValueChanged(ValueNode
* valueNode
)
1296 AutoLocker
<ValueNodeContainer
> containerLocker(
1297 fNodeManager
->GetContainer());
1299 // check whether we know the node
1300 ValueNodeChild
* nodeChild
= valueNode
->NodeChild();
1301 if (nodeChild
== NULL
)
1304 ModelNode
* modelNode
= fNodeTable
.Lookup(nodeChild
);
1305 if (modelNode
== NULL
)
1308 // check whether the value actually changed
1309 Value
* value
= valueNode
->GetValue();
1310 if (value
== modelNode
->GetValue())
1313 // get a value handler
1314 ValueHandler
* valueHandler
;
1315 status_t error
= ValueHandlerRoster::Default()->FindValueHandler(value
,
1319 BReference
<ValueHandler
> handlerReference(valueHandler
, true);
1321 // create a table cell renderer for the value
1322 TableCellValueRenderer
* renderer
= NULL
;
1323 error
= valueHandler
->GetTableCellValueRenderer(value
, renderer
);
1327 // set value/handler/renderer
1328 modelNode
->SetValue(value
);
1329 modelNode
->SetValueHandler(valueHandler
);
1330 modelNode
->SetTableCellRenderer(renderer
);
1332 // we have to restore renderer settings here since until this point
1333 // we don't yet know what renderer is in use.
1334 if (renderer
!= NULL
) {
1335 Settings
* settings
= renderer
->GetSettings();
1336 if (settings
!= NULL
)
1337 settings
->RestoreValues(modelNode
->GetLastRendererSettings());
1342 // notify table model listeners
1343 NotifyNodeChanged(modelNode
);
1348 VariablesView::VariableTableModel::CountColumns() const
1355 VariablesView::VariableTableModel::Root() const
1362 VariablesView::VariableTableModel::CountChildren(void* parent
) const
1365 return fNodes
.CountItems();
1367 // If the node only has a hidden child, pretend the node directly has the
1368 // child's children.
1369 ModelNode
* modelNode
= (ModelNode
*)parent
;
1370 int32 childCount
= modelNode
->CountChildren();
1371 if (childCount
== 1) {
1372 ModelNode
* child
= modelNode
->ChildAt(0);
1373 if (child
->IsHidden())
1374 return child
->CountChildren();
1382 VariablesView::VariableTableModel::ChildAt(void* parent
, int32 index
) const
1385 return fNodes
.ItemAt(index
);
1387 // If the node only has a hidden child, pretend the node directly has the
1388 // child's children.
1389 ModelNode
* modelNode
= (ModelNode
*)parent
;
1390 int32 childCount
= modelNode
->CountChildren();
1391 if (childCount
== 1) {
1392 ModelNode
* child
= modelNode
->ChildAt(0);
1393 if (child
->IsHidden())
1394 return child
->ChildAt(index
);
1397 return modelNode
->ChildAt(index
);
1402 VariablesView::VariableTableModel::GetValueAt(void* object
, int32 columnIndex
,
1405 ModelNode
* node
= (ModelNode
*)object
;
1407 switch (columnIndex
) {
1409 _value
.SetTo(node
->Name(), B_VARIANT_DONT_COPY_DATA
);
1412 if (node
->GetValue() == NULL
) {
1413 ValueLocation
* location
= node
->NodeChild()->Location();
1414 if (location
== NULL
)
1417 ValueNode
* childNode
= node
->NodeChild()->Node();
1418 if (childNode
== NULL
)
1421 Type
* nodeChildRawType
= childNode
->GetType()->ResolveRawType(
1423 if (nodeChildRawType
->Kind() == TYPE_COMPOUND
)
1425 if (location
->CountPieces() > 1)
1429 ValuePieceLocation piece
= location
->PieceAt(0);
1430 if (piece
.type
!= VALUE_PIECE_LOCATION_MEMORY
)
1433 data
.SetToFormat("[@ %#" B_PRIx64
"]", piece
.address
);
1440 _value
.SetTo(node
, VALUE_NODE_TYPE
);
1444 // use the type of the underlying value node, as it may
1445 // be different from the initially assigned top level type
1447 ValueNode
* childNode
= node
->NodeChild()->Node();
1448 if (childNode
== NULL
)
1451 Type
* type
= childNode
->GetType();
1455 _value
.SetTo(type
->Name(), B_VARIANT_DONT_COPY_DATA
);
1465 VariablesView::VariableTableModel::NodeExpanded(ModelNode
* node
)
1467 AutoLocker
<ValueNodeContainer
> containerLocker(
1468 fNodeManager
->GetContainer());
1469 // add children of all children
1471 // If the node only has a hidden child, add the child's children instead.
1472 if (node
->CountChildren() == 1) {
1473 ModelNode
* child
= node
->ChildAt(0);
1474 if (child
->IsHidden())
1479 for (int32 i
= 0; ModelNode
* child
= node
->ChildAt(i
); i
++)
1480 fNodeManager
->AddChildNodes(child
->NodeChild());
1485 VariablesView::VariableTableModel::NotifyNodeChanged(ModelNode
* node
)
1487 if (!node
->IsHidden()) {
1488 TreeTablePath treePath
;
1489 if (GetTreePath(node
, treePath
)) {
1490 int32 index
= treePath
.RemoveLastComponent();
1491 NotifyNodesChanged(treePath
, index
, 1);
1498 VariablesView::VariableTableModel::NotifyNodeHidden(ModelNode
* node
)
1500 fContainerListener
->ModelNodeHidden(node
);
1505 VariablesView::VariableTableModel::GetToolTipForTablePath(
1506 const TreeTablePath
& path
, int32 columnIndex
, BToolTip
** _tip
)
1508 ModelNode
* node
= (ModelNode
*)NodeForPath(path
);
1513 ValueNodeChild
* child
= node
->NodeChild();
1514 status_t error
= child
->LocationResolutionState();
1516 tipData
.SetToFormat("Unable to resolve location: %s", strerror(error
));
1518 ValueNode
* valueNode
= child
->Node();
1519 if (valueNode
== NULL
)
1521 error
= valueNode
->LocationAndValueResolutionState();
1522 if (error
!= B_OK
) {
1523 tipData
.SetToFormat("Unable to resolve value: %s\n\n",
1527 switch (columnIndex
) {
1530 ValueLocation
* location
= child
->Location();
1531 for (int32 i
= 0; i
< location
->CountPieces(); i
++) {
1532 ValuePieceLocation piece
= location
->PieceAt(i
);
1534 switch (piece
.type
) {
1535 case VALUE_PIECE_LOCATION_MEMORY
:
1536 pieceData
.SetToFormat("(%" B_PRId32
"): Address: "
1537 "%#" B_PRIx64
", Size: %" B_PRId64
" bytes\n",
1538 i
, piece
.address
, piece
.size
);
1540 case VALUE_PIECE_LOCATION_REGISTER
:
1542 Architecture
* architecture
= fThread
->GetTeam()
1543 ->GetArchitecture();
1544 pieceData
.SetToFormat("(%" B_PRId32
"): Register "
1546 architecture
->Registers()[piece
.reg
].Name());
1553 tipData
+= pieceData
;
1555 tipData
+= "Editable: ";
1556 tipData
+= error
== B_OK
&& location
->IsWritable()
1562 Value
* value
= node
->GetValue();
1564 value
->ToString(tipData
);
1573 if (tipData
.IsEmpty())
1576 *_tip
= new(std::nothrow
) BTextToolTip(tipData
);
1585 VariablesView::VariableTableModel::AddSyntheticNode(Variable
* variable
,
1586 ValueNodeChild
*& _child
, const char* presentationName
)
1588 ValueNodeContainer
* container
= fNodeManager
->GetContainer();
1589 AutoLocker
<ValueNodeContainer
> containerLocker(container
);
1592 if (_child
== NULL
) {
1593 _child
= new(std::nothrow
) VariableValueNodeChild(variable
);
1597 BReference
<ValueNodeChild
> childReference(_child
, true);
1598 ValueNode
* valueNode
;
1599 if (_child
->IsInternal())
1600 error
= _child
->CreateInternalNode(valueNode
);
1602 error
= TypeHandlerRoster::Default()->CreateValueNode(_child
,
1603 _child
->GetType(), valueNode
);
1609 _child
->SetNode(valueNode
);
1610 valueNode
->ReleaseReference();
1613 container
->AddChild(_child
);
1615 error
= _AddNode(variable
, NULL
, _child
);
1616 if (error
!= B_OK
) {
1617 container
->RemoveChild(_child
);
1621 // since we're injecting these nodes synthetically,
1622 // we have to manually ask the node manager to create any
1623 // applicable children; this would normally be done implicitly
1624 // for top level nodes, as they're added from the parameters/locals,
1626 fNodeManager
->AddChildNodes(_child
);
1628 ModelNode
* childNode
= fNodeTable
.Lookup(_child
);
1629 if (childNode
!= NULL
) {
1630 if (presentationName
!= NULL
)
1631 childNode
->SetPresentationName(presentationName
);
1633 ValueNode
* valueNode
= _child
->Node();
1634 if (valueNode
->LocationAndValueResolutionState()
1635 == VALUE_NODE_UNRESOLVED
) {
1636 fContainerListener
->ModelNodeValueRequested(childNode
);
1638 ValueNodeValueChanged(valueNode
);
1640 ValueNodeChildrenCreated(_child
->Node());
1647 VariablesView::VariableTableModel::RemoveSyntheticNode(ModelNode
* node
)
1649 int32 index
= fNodes
.IndexOf(node
);
1653 fNodeTable
.Remove(node
);
1655 fNodes
.RemoveItemAt(index
);
1657 NotifyNodesRemoved(TreeTablePath(), index
, 1);
1659 node
->ReleaseReference();
1664 VariablesView::VariableTableModel::_AddNode(Variable
* variable
,
1665 ModelNode
* parent
, ValueNodeChild
* nodeChild
, bool isPresentationNode
,
1668 // Don't create nodes for unspecified types -- we can't get/show their
1670 Type
* nodeChildRawType
= nodeChild
->GetType()->ResolveRawType(false);
1671 if (nodeChildRawType
->Kind() == TYPE_UNSPECIFIED
)
1674 ModelNode
* node
= new(std::nothrow
) ModelNode(parent
, variable
, nodeChild
,
1675 isPresentationNode
);
1676 BReference
<ModelNode
> nodeReference(node
, true);
1677 if (node
== NULL
|| node
->Init() != B_OK
)
1682 if (parent
!= NULL
) {
1683 childIndex
= parent
->CountChildren();
1685 if (!parent
->AddChild(node
))
1687 // the parent has a reference, now
1689 childIndex
= fNodes
.CountItems();
1691 if (!fNodes
.AddItem(node
))
1693 nodeReference
.Detach();
1694 // the fNodes list has a reference, now
1697 fNodeTable
.Insert(node
);
1699 // if an address type node has only a single child, and that child
1700 // is a compound type, mark it hidden
1701 if (isOnlyChild
&& parent
!= NULL
) {
1702 ValueNode
* parentValueNode
= parent
->NodeChild()->Node();
1703 if (parentValueNode
!= NULL
) {
1704 if (parentValueNode
->GetType()->ResolveRawType(false)->Kind()
1706 type_kind childKind
= nodeChildRawType
->Kind();
1707 if (childKind
== TYPE_COMPOUND
|| childKind
== TYPE_ARRAY
) {
1708 node
->SetHidden(true);
1710 // we need to tell the listener about nodes like this so
1711 // any necessary actions can be taken for them (i.e. value
1712 // resolution), since they're otherwise invisible to
1714 NotifyNodeHidden(node
);
1720 // notify table model listeners
1721 if (!node
->IsHidden()) {
1723 if (parent
== NULL
|| GetTreePath(parent
, path
))
1724 NotifyNodesAdded(path
, childIndex
, 1);
1727 // if the node is hidden, add its children
1728 if (node
->IsHidden())
1729 fNodeManager
->AddChildNodes(nodeChild
);
1736 VariablesView::VariableTableModel::GetTreePath(ModelNode
* node
,
1737 TreeTablePath
& _path
) const
1739 // recurse, if the node has a parent
1740 if (ModelNode
* parent
= node
->Parent()) {
1741 if (!GetTreePath(parent
, _path
))
1744 if (node
->IsHidden())
1747 return _path
.AddComponent(parent
->IndexOf(node
));
1750 // no parent -- get the index and start the path
1751 int32 index
= fNodes
.IndexOf(node
);
1753 return index
>= 0 && _path
.AddComponent(index
);
1757 // #pragma mark - VariablesView
1760 VariablesView::VariablesView(Listener
* listener
)
1762 BGroupView(B_VERTICAL
),
1765 fVariableTable(NULL
),
1766 fVariableTableModel(NULL
),
1767 fContainerListener(NULL
),
1768 fPreviousViewState(NULL
),
1769 fViewStateHistory(NULL
),
1771 fExpressionChildren(10, false),
1772 fTableCellContextMenuTracker(NULL
),
1773 fPendingTypecastInfo(NULL
),
1774 fTemporaryExpression(NULL
),
1775 fFrameClearPending(false),
1779 SetName("Variables");
1783 VariablesView::~VariablesView()
1785 if (fEditWindow
!= NULL
)
1786 BMessenger(fEditWindow
).SendMessage(B_QUIT_REQUESTED
);
1788 SetStackFrame(NULL
, NULL
);
1789 fVariableTable
->SetTreeTableModel(NULL
);
1791 if (fPreviousViewState
!= NULL
)
1792 fPreviousViewState
->ReleaseReference();
1793 delete fViewStateHistory
;
1795 if (fVariableTableModel
!= NULL
) {
1796 fVariableTableModel
->SetContainerListener(NULL
);
1797 delete fVariableTableModel
;
1800 delete fContainerListener
;
1801 if (fPendingTypecastInfo
!= NULL
)
1802 fPendingTypecastInfo
->ReleaseReference();
1804 if (fTemporaryExpression
!= NULL
)
1805 fTemporaryExpression
->ReleaseReference();
1809 /*static*/ VariablesView
*
1810 VariablesView::Create(Listener
* listener
, ValueNodeManager
* manager
)
1812 VariablesView
* self
= new VariablesView(listener
);
1815 self
->_Init(manager
);
1826 VariablesView::SetStackFrame(::Thread
* thread
, StackFrame
* stackFrame
)
1828 bool updateValues
= fFrameClearPending
;
1829 // We only want to save previous values if we've continued
1830 // execution (i.e. thread/frame are being cleared).
1831 // Otherwise, we'll overwrite our previous values simply
1832 // by switching frames within the same stack trace, which isn't
1833 // desired behavior.
1835 fFrameClearPending
= false;
1837 if (thread
== fThread
&& stackFrame
== fStackFrame
)
1840 _SaveViewState(updateValues
);
1842 _FinishContextMenu(true);
1844 for (int32 i
= 0; i
< fExpressionChildren
.CountItems(); i
++)
1845 fExpressionChildren
.ItemAt(i
)->ReleaseReference();
1846 fExpressionChildren
.MakeEmpty();
1848 if (fThread
!= NULL
)
1849 fThread
->ReleaseReference();
1850 if (fStackFrame
!= NULL
)
1851 fStackFrame
->ReleaseReference();
1854 fStackFrame
= stackFrame
;
1856 if (fThread
!= NULL
)
1857 fThread
->AcquireReference();
1858 if (fStackFrame
!= NULL
)
1859 fStackFrame
->AcquireReference();
1861 fVariableTableModel
->SetStackFrame(fThread
, fStackFrame
);
1863 // request loading the parameter and variable values
1864 if (fThread
!= NULL
&& fStackFrame
!= NULL
) {
1865 AutoLocker
<Team
> locker(fThread
->GetTeam());
1867 void* root
= fVariableTableModel
->Root();
1868 int32 count
= fVariableTableModel
->CountChildren(root
);
1869 for (int32 i
= 0; i
< count
; i
++) {
1870 ModelNode
* node
= (ModelNode
*)fVariableTableModel
->ChildAt(root
, i
);
1871 _RequestNodeValue(node
);
1874 _RestoreExpressionNodes();
1877 _RestoreViewState();
1882 VariablesView::MessageReceived(BMessage
* message
)
1884 switch (message
->what
) {
1885 case MSG_SHOW_INSPECTOR_WINDOW
:
1887 // TODO: it'd probably be more ideal to extend the context
1888 // action mechanism to allow one to specify an explicit
1889 // target for each action rather than them all defaulting
1890 // to targetting here.
1891 Looper()->PostMessage(message
);
1894 case MSG_SHOW_VARIABLE_EDIT_WINDOW
:
1896 if (fEditWindow
!= NULL
)
1897 fEditWindow
->Activate();
1899 ModelNode
* node
= NULL
;
1900 if (message
->FindPointer("node", reinterpret_cast<void**>(
1905 Value
* value
= NULL
;
1906 if (message
->FindPointer("value", reinterpret_cast<void**>(
1911 _HandleEditVariableRequest(node
, value
);
1915 case MSG_VARIABLE_EDIT_WINDOW_CLOSED
:
1920 case MSG_WRITE_VARIABLE_VALUE
:
1922 Value
* value
= NULL
;
1923 if (message
->FindPointer("value", reinterpret_cast<void**>(
1928 BReference
<Value
> valueReference(value
, true);
1930 ValueNode
* node
= NULL
;
1931 if (message
->FindPointer("node", reinterpret_cast<void**>(
1936 fListener
->ValueNodeWriteRequested(node
,
1937 fStackFrame
->GetCpuState(), value
);
1940 case MSG_SHOW_TYPECAST_NODE_PROMPT
:
1942 BMessage
* promptMessage
= new(std::nothrow
) BMessage(
1945 if (promptMessage
== NULL
)
1948 ObjectDeleter
<BMessage
> messageDeleter(promptMessage
);
1949 promptMessage
->AddPointer("node", fVariableTable
1950 ->SelectionModel()->NodeAt(0));
1951 PromptWindow
* promptWindow
= new(std::nothrow
) PromptWindow(
1952 "Specify Type", "Type: ", NULL
, BMessenger(this),
1954 if (promptWindow
== NULL
)
1957 messageDeleter
.Detach();
1958 promptWindow
->CenterOnScreen();
1959 promptWindow
->Show();
1962 case MSG_TYPECAST_NODE
:
1964 ModelNode
* node
= NULL
;
1965 if (message
->FindPointer("node", reinterpret_cast<void **>(&node
))
1970 BString typeExpression
;
1971 if (message
->FindString("text", &typeExpression
) == B_OK
) {
1972 if (typeExpression
.IsEmpty())
1975 if (fPendingTypecastInfo
!= NULL
)
1976 fPendingTypecastInfo
->ReleaseReference();
1978 fPendingTypecastInfo
= new(std::nothrow
)
1979 VariablesExpressionInfo(typeExpression
, node
);
1980 if (fPendingTypecastInfo
== NULL
) {
1981 // TODO: notify user
1985 fPendingTypecastInfo
->AddListener(this);
1986 fListener
->ExpressionEvaluationRequested(fPendingTypecastInfo
,
1987 fStackFrame
, fThread
);
1991 case MSG_TYPECAST_TO_ARRAY
:
1993 ModelNode
* node
= NULL
;
1994 if (message
->FindPointer("node", reinterpret_cast<void **>(&node
))
1999 Type
* baseType
= dynamic_cast<AddressType
*>(node
->NodeChild()
2000 ->Node()->GetType())->BaseType();
2001 ArrayType
* arrayType
= NULL
;
2002 if (baseType
->CreateDerivedArrayType(0, kMaxArrayElementCount
,
2003 false, arrayType
) != B_OK
) {
2007 AddressType
* addressType
= NULL
;
2008 BReference
<Type
> typeRef(arrayType
, true);
2009 if (arrayType
->CreateDerivedAddressType(DERIVED_TYPE_POINTER
,
2010 addressType
) != B_OK
) {
2015 typeRef
.SetTo(addressType
, true);
2016 ValueNode
* valueNode
= NULL
;
2017 if (TypeHandlerRoster::Default()->CreateValueNode(
2018 node
->NodeChild(), addressType
, valueNode
) != B_OK
) {
2023 node
->NodeChild()->SetNode(valueNode
);
2024 node
->SetCastedType(addressType
);
2025 fVariableTableModel
->NotifyNodeChanged(node
);
2028 case MSG_SHOW_CONTAINER_RANGE_PROMPT
:
2030 ModelNode
* node
= (ModelNode
*)fVariableTable
2031 ->SelectionModel()->NodeAt(0);
2032 int32 lowerBound
, upperBound
;
2033 ValueNode
* valueNode
= node
->NodeChild()->Node();
2034 if (!valueNode
->IsRangedContainer()) {
2035 valueNode
= node
->ChildAt(0)->NodeChild()->Node();
2036 if (!valueNode
->IsRangedContainer())
2040 bool fixedRange
= valueNode
->IsContainerRangeFixed();
2041 if (valueNode
->SupportedChildRange(lowerBound
, upperBound
)
2046 BMessage
* promptMessage
= new(std::nothrow
) BMessage(
2047 MSG_SET_CONTAINER_RANGE
);
2048 if (promptMessage
== NULL
)
2051 ObjectDeleter
<BMessage
> messageDeleter(promptMessage
);
2052 promptMessage
->AddPointer("node", node
);
2053 promptMessage
->AddBool("fixedRange", fixedRange
);
2056 infoText
.SetToFormat("Allowed range: %" B_PRId32
2057 "-%" B_PRId32
".", lowerBound
, upperBound
);
2059 infoText
.SetToFormat("Current range: %" B_PRId32
2060 "-%" B_PRId32
".", lowerBound
, upperBound
);
2063 PromptWindow
* promptWindow
= new(std::nothrow
) PromptWindow(
2064 "Set Range", "Range: ", infoText
.String(), BMessenger(this),
2066 if (promptWindow
== NULL
)
2069 messageDeleter
.Detach();
2070 promptWindow
->CenterOnScreen();
2071 promptWindow
->Show();
2074 case MSG_SET_CONTAINER_RANGE
:
2076 ModelNode
* node
= (ModelNode
*)fVariableTable
2077 ->SelectionModel()->NodeAt(0);
2078 int32 lowerBound
, upperBound
;
2079 ValueNode
* valueNode
= node
->NodeChild()->Node();
2080 if (!valueNode
->IsRangedContainer())
2081 valueNode
= node
->ChildAt(0)->NodeChild()->Node();
2082 if (valueNode
->SupportedChildRange(lowerBound
, upperBound
) != B_OK
)
2085 bool fixedRange
= message
->FindBool("fixedRange");
2087 BString rangeExpression
= message
->FindString("text");
2088 if (rangeExpression
.Length() == 0)
2092 status_t result
= UiUtils::ParseRangeExpression(
2093 rangeExpression
, lowerBound
, upperBound
, fixedRange
, ranges
);
2097 valueNode
->ClearChildren();
2098 for (int32 i
= 0; i
< ranges
.CountRanges(); i
++) {
2099 const Range
* range
= ranges
.RangeAt(i
);
2100 result
= valueNode
->CreateChildrenInRange(
2101 fThread
->GetTeam()->GetTeamTypeInformation(),
2102 range
->lowerBound
, range
->upperBound
);
2108 case MSG_SHOW_WATCH_VARIABLE_PROMPT
:
2110 ModelNode
* node
= reinterpret_cast<ModelNode
*>(
2111 fVariableTable
->SelectionModel()->NodeAt(0));
2112 ValueLocation
* location
= node
->NodeChild()->Location();
2113 ValuePieceLocation piece
= location
->PieceAt(0);
2114 if (piece
.type
!= VALUE_PIECE_LOCATION_MEMORY
)
2117 BMessage
looperMessage(*message
);
2118 looperMessage
.AddUInt64("address", piece
.address
);
2119 looperMessage
.AddInt32("length", piece
.size
);
2120 looperMessage
.AddUInt32("type", B_DATA_READ_WRITE_WATCHPOINT
);
2121 Looper()->PostMessage(&looperMessage
);
2124 case MSG_ADD_WATCH_EXPRESSION
:
2126 BMessage
looperMessage(MSG_SHOW_EXPRESSION_PROMPT_WINDOW
);
2127 looperMessage
.AddPointer("target", this);
2128 Looper()->PostMessage(&looperMessage
);
2131 case MSG_REMOVE_WATCH_EXPRESSION
:
2134 if (message
->FindPointer("node", reinterpret_cast<void**>(&node
))
2139 _RemoveExpression(node
);
2142 case MSG_ADD_NEW_EXPRESSION
:
2144 const char* expression
;
2145 if (message
->FindString("expression", &expression
) != B_OK
)
2148 bool persistentExpression
= message
->FindBool("persistent");
2150 ExpressionInfo
* info
;
2151 status_t error
= _AddExpression(expression
, persistentExpression
,
2153 if (error
!= B_OK
) {
2154 // TODO: notify user of failure
2158 fListener
->ExpressionEvaluationRequested(info
, fStackFrame
,
2162 case MSG_EXPRESSION_EVALUATED
:
2164 ExpressionInfo
* info
;
2166 ExpressionResult
* value
= NULL
;
2167 if (message
->FindPointer("info",
2168 reinterpret_cast<void**>(&info
)) != B_OK
2169 || message
->FindInt32("result", &result
) != B_OK
) {
2173 BReference
<ExpressionResult
> valueReference
;
2174 if (message
->FindPointer("value", reinterpret_cast<void**>(&value
))
2176 valueReference
.SetTo(value
, true);
2179 VariablesExpressionInfo
* variableInfo
2180 = dynamic_cast<VariablesExpressionInfo
*>(info
);
2181 if (variableInfo
!= NULL
) {
2182 if (fPendingTypecastInfo
== variableInfo
) {
2183 _HandleTypecastResult(result
, value
);
2184 fPendingTypecastInfo
->ReleaseReference();
2185 fPendingTypecastInfo
= NULL
;
2188 _AddExpressionNode(info
, result
, value
);
2189 if (info
== fTemporaryExpression
) {
2190 info
->ReleaseReference();
2191 fTemporaryExpression
= NULL
;
2197 case MSG_VALUE_NODE_CHANGED
:
2199 ValueNodeChild
* nodeChild
;
2202 if (message
->FindPointer("nodeChild", (void**)&nodeChild
) == B_OK
2203 && message
->FindPointer("oldNode", (void**)&oldNode
) == B_OK
2204 && message
->FindPointer("newNode", (void**)&newNode
) == B_OK
) {
2205 BReference
<ValueNodeChild
> nodeChildReference(nodeChild
, true);
2206 BReference
<ValueNode
> oldNodeReference(oldNode
, true);
2207 BReference
<ValueNode
> newNodeReference(newNode
, true);
2209 fVariableTableModel
->ValueNodeChanged(nodeChild
, oldNode
,
2215 case MSG_VALUE_NODE_CHILDREN_CREATED
:
2218 if (message
->FindPointer("node", (void**)&node
) == B_OK
) {
2219 BReference
<ValueNode
> newNodeReference(node
, true);
2220 fVariableTableModel
->ValueNodeChildrenCreated(node
);
2225 case MSG_VALUE_NODE_CHILDREN_DELETED
:
2228 if (message
->FindPointer("node", (void**)&node
) == B_OK
) {
2229 BReference
<ValueNode
> newNodeReference(node
, true);
2230 fVariableTableModel
->ValueNodeChildrenDeleted(node
);
2235 case MSG_VALUE_NODE_VALUE_CHANGED
:
2238 if (message
->FindPointer("node", (void**)&node
) == B_OK
) {
2239 BReference
<ValueNode
> newNodeReference(node
, true);
2240 fVariableTableModel
->ValueNodeValueChanged(node
);
2245 case MSG_RESTORE_PARTIAL_VIEW_STATE
:
2248 if (message
->FindPointer("node", (void**)&node
) == B_OK
) {
2250 if (fVariableTableModel
->GetTreePath(node
, path
)) {
2251 FunctionID
* functionID
= fStackFrame
->Function()
2253 if (functionID
== NULL
)
2255 BReference
<FunctionID
> functionIDReference(functionID
,
2257 VariablesViewState
* viewState
= fViewStateHistory
2258 ->GetState(fThread
->ID(), functionID
);
2259 if (viewState
!= NULL
) {
2260 _ApplyViewStateDescendentNodeInfos(viewState
, node
,
2267 case MSG_VALUE_NODE_NEEDS_VALUE
:
2268 case MSG_MODEL_NODE_HIDDEN
:
2271 if (message
->FindPointer("node", (void**)&node
) == B_OK
) {
2272 BReference
<ModelNode
> modelNodeReference(node
, true);
2273 _RequestNodeValue(node
);
2278 case MSG_VARIABLES_VIEW_CONTEXT_MENU_DONE
:
2280 _FinishContextMenu(false);
2283 case MSG_VARIABLES_VIEW_NODE_SETTINGS_CHANGED
:
2286 if (message
->FindPointer("node", (void**)&node
) != B_OK
)
2288 BReference
<ModelNode
> nodeReference(node
, true);
2290 fVariableTableModel
->NotifyNodeChanged(node
);
2295 _CopyVariableValueToClipboard();
2299 BGroupView::MessageReceived(message
);
2306 VariablesView::DetachedFromWindow()
2308 _FinishContextMenu(true);
2313 VariablesView::LoadSettings(const BMessage
& settings
)
2315 BMessage tableSettings
;
2316 if (settings
.FindMessage("variableTable", &tableSettings
) == B_OK
) {
2317 GuiSettingsUtils::UnarchiveTableSettings(tableSettings
,
2324 VariablesView::SaveSettings(BMessage
& settings
)
2326 settings
.MakeEmpty();
2328 BMessage tableSettings
;
2329 status_t result
= GuiSettingsUtils::ArchiveTableSettings(tableSettings
,
2332 result
= settings
.AddMessage("variableTable", &tableSettings
);
2339 VariablesView::SetStackFrameClearPending()
2341 fFrameClearPending
= true;
2346 VariablesView::TreeTableNodeExpandedChanged(TreeTable
* table
,
2347 const TreeTablePath
& path
, bool expanded
)
2349 if (fFrameClearPending
)
2353 ModelNode
* node
= (ModelNode
*)fVariableTableModel
->NodeForPath(path
);
2357 fVariableTableModel
->NodeExpanded(node
);
2359 // request the values of all children that don't have any yet
2361 // If the node only has a hidden child, directly load the child's
2362 // children's values.
2363 if (node
->CountChildren() == 1) {
2364 ModelNode
* child
= node
->ChildAt(0);
2365 if (child
->IsHidden())
2369 // request the values
2370 for (int32 i
= 0; ModelNode
* child
= node
->ChildAt(i
); i
++) {
2371 if (child
->IsPresentationNode())
2374 _RequestNodeValue(child
);
2381 VariablesView::TreeTableNodeInvoked(TreeTable
* table
,
2382 const TreeTablePath
& path
)
2384 ModelNode
* node
= (ModelNode
*)fVariableTableModel
->NodeForPath(path
);
2388 ValueNodeChild
* child
= node
->NodeChild();
2390 if (child
->LocationResolutionState() != B_OK
)
2393 ValueLocation
* location
= child
->Location();
2394 if (!location
->IsWritable())
2397 Value
* value
= node
->GetValue();
2401 BMessage
message(MSG_SHOW_VARIABLE_EDIT_WINDOW
);
2402 message
.AddPointer("node", node
);
2403 message
.AddPointer("value", value
);
2405 BMessenger(this).SendMessage(&message
);
2410 VariablesView::TreeTableCellMouseDown(TreeTable
* table
,
2411 const TreeTablePath
& path
, int32 columnIndex
, BPoint screenWhere
,
2414 if ((buttons
& B_SECONDARY_MOUSE_BUTTON
) == 0)
2417 if (fFrameClearPending
)
2420 _FinishContextMenu(true);
2422 ModelNode
* node
= (ModelNode
*)fVariableTableModel
->NodeForPath(path
);
2426 Settings
* settings
= NULL
;
2427 SettingsMenu
* settingsMenu
= NULL
;
2428 BReference
<SettingsMenu
> settingsMenuReference
;
2429 status_t error
= B_OK
;
2430 TableCellValueRenderer
* cellRenderer
= node
->TableCellRenderer();
2431 if (cellRenderer
!= NULL
) {
2432 settings
= cellRenderer
->GetSettings();
2433 if (settings
!= NULL
) {
2434 error
= node
->GetValueHandler()
2435 ->CreateTableCellValueSettingsMenu(node
->GetValue(), settings
,
2437 settingsMenuReference
.SetTo(settingsMenu
, true);
2443 TableCellContextMenuTracker
* tracker
= new(std::nothrow
)
2444 TableCellContextMenuTracker(node
, Looper(), this);
2445 BReference
<TableCellContextMenuTracker
> trackerReference(tracker
);
2447 ContextActionList
* preActionList
;
2448 ContextActionList
* postActionList
;
2450 error
= _GetContextActionsForNode(node
, preActionList
, postActionList
);
2454 BPrivate::ObjectDeleter
<ContextActionList
> preActionListDeleter(
2457 BPrivate::ObjectDeleter
<ContextActionList
> postActionListDeleter(
2460 if (tracker
== NULL
|| tracker
->Init(settings
, settingsMenu
, preActionList
,
2461 postActionList
) != B_OK
) {
2465 fTableCellContextMenuTracker
= trackerReference
.Detach();
2466 fTableCellContextMenuTracker
->ShowMenu(screenWhere
);
2471 VariablesView::ExpressionEvaluated(ExpressionInfo
* info
, status_t result
,
2472 ExpressionResult
* value
)
2474 BMessage
message(MSG_EXPRESSION_EVALUATED
);
2475 message
.AddPointer("info", info
);
2476 message
.AddInt32("result", result
);
2477 BReference
<ExpressionResult
> valueReference
;
2479 if (value
!= NULL
) {
2480 valueReference
.SetTo(value
);
2481 message
.AddPointer("value", value
);
2484 if (BMessenger(this).SendMessage(&message
) == B_OK
)
2485 valueReference
.Detach();
2490 VariablesView::_Init(ValueNodeManager
* manager
)
2492 fVariableTable
= new TreeTable("variable list", 0, B_FANCY_BORDER
);
2493 AddChild(fVariableTable
->ToView());
2494 fVariableTable
->SetSortingEnabled(false);
2497 fVariableTable
->AddColumn(new StringTableColumn(0, "Variable", 80, 40, 1000,
2498 B_TRUNCATE_END
, B_ALIGN_LEFT
));
2499 fVariableTable
->AddColumn(new VariableValueColumn(1, "Value", 80, 40, 1000,
2500 B_TRUNCATE_END
, B_ALIGN_RIGHT
));
2501 fVariableTable
->AddColumn(new StringTableColumn(2, "Type", 80, 40, 1000,
2502 B_TRUNCATE_END
, B_ALIGN_LEFT
));
2504 fVariableTableModel
= new VariableTableModel(manager
);
2505 if (fVariableTableModel
->Init() != B_OK
)
2506 throw std::bad_alloc();
2507 fVariableTable
->SetTreeTableModel(fVariableTableModel
);
2508 fVariableTable
->SetToolTipProvider(fVariableTableModel
);
2510 fContainerListener
= new ContainerListener(this);
2511 fVariableTableModel
->SetContainerListener(fContainerListener
);
2513 fVariableTable
->AddTreeTableListener(this);
2515 fViewStateHistory
= new VariablesViewStateHistory
;
2516 if (fViewStateHistory
->Init() != B_OK
)
2517 throw std::bad_alloc();
2519 fExpressions
= new ExpressionInfoTable();
2520 if (fExpressions
->Init() != B_OK
)
2521 throw std::bad_alloc();
2526 VariablesView::_RequestNodeValue(ModelNode
* node
)
2528 // get the node child and its container
2529 ValueNodeChild
* nodeChild
= node
->NodeChild();
2530 ValueNodeContainer
* container
= nodeChild
->Container();
2532 BReference
<ValueNodeContainer
> containerReference(container
);
2533 AutoLocker
<ValueNodeContainer
> containerLocker(container
);
2535 if (container
== NULL
|| nodeChild
->Container() != container
)
2538 // get the value node and check whether its value has not yet been resolved
2539 ValueNode
* valueNode
= nodeChild
->Node();
2540 if (valueNode
== NULL
) {
2541 ModelNode
* parent
= node
->Parent();
2542 if (parent
!= NULL
) {
2544 if (!fVariableTableModel
->GetTreePath(parent
, path
))
2547 // if the parent node was already expanded when the child was
2548 // added, we may not yet have added a value node.
2549 // Notify the table model that this needs to be done.
2550 if (fVariableTable
->IsNodeExpanded(path
))
2551 fVariableTableModel
->NodeExpanded(parent
);
2555 if (valueNode
== NULL
|| valueNode
->LocationAndValueResolutionState()
2556 != VALUE_NODE_UNRESOLVED
) {
2560 BReference
<ValueNode
> valueNodeReference(valueNode
);
2561 containerLocker
.Unlock();
2563 // request resolution of the value
2564 fListener
->ValueNodeValueRequested(fStackFrame
!= NULL
2565 ? fStackFrame
->GetCpuState() : NULL
, container
, valueNode
);
2570 VariablesView::_GetContextActionsForNode(ModelNode
* node
,
2571 ContextActionList
*& _preActions
, ContextActionList
*& _postActions
)
2574 _postActions
= NULL
;
2576 ValueLocation
* location
= node
->NodeChild()->Location();
2578 _preActions
= new(std::nothrow
) ContextActionList
;
2579 if (_preActions
== NULL
)
2582 BPrivate::ObjectDeleter
<ContextActionList
> preActionListDeleter(
2585 status_t result
= B_OK
;
2586 BMessage
* message
= NULL
;
2588 // only show the Inspect option if the value is in fact located
2590 if (location
!= NULL
) {
2591 if (location
->PieceAt(0).type
== VALUE_PIECE_LOCATION_MEMORY
) {
2592 result
= _AddContextAction("Inspect", MSG_SHOW_INSPECTOR_WINDOW
,
2593 _preActions
, message
);
2596 message
->AddUInt64("address", location
->PieceAt(0).address
);
2599 ValueNode
* valueNode
= node
->NodeChild()->Node();
2601 if (valueNode
!= NULL
) {
2602 Value
* value
= valueNode
->GetValue();
2603 if (location
->IsWritable() && value
!= NULL
) {
2604 result
= _AddContextAction("Edit" B_UTF8_ELLIPSIS
,
2605 MSG_SHOW_VARIABLE_EDIT_WINDOW
, _preActions
, message
);
2608 message
->AddPointer("node", node
);
2609 message
->AddPointer("value", value
);
2611 AddressType
* type
= dynamic_cast<AddressType
*>(valueNode
->GetType());
2612 if (type
!= NULL
&& type
->BaseType() != NULL
) {
2613 result
= _AddContextAction("Cast to array", MSG_TYPECAST_TO_ARRAY
,
2614 _preActions
, message
);
2617 message
->AddPointer("node", node
);
2621 result
= _AddContextAction("Cast as" B_UTF8_ELLIPSIS
,
2622 MSG_SHOW_TYPECAST_NODE_PROMPT
, _preActions
, message
);
2626 result
= _AddContextAction("Watch" B_UTF8_ELLIPSIS
,
2627 MSG_SHOW_WATCH_VARIABLE_PROMPT
, _preActions
, message
);
2631 if (valueNode
== NULL
)
2634 if (valueNode
->LocationAndValueResolutionState() == B_OK
) {
2635 result
= _AddContextAction("Copy Value", B_COPY
, _preActions
, message
);
2640 bool addRangedContainerItem
= false;
2641 // if the current node isn't itself a ranged container, check if it
2642 // contains a hidden node which is, since in the latter case we
2643 // want to present the range selection as well.
2644 if (valueNode
->IsRangedContainer())
2645 addRangedContainerItem
= true;
2646 else if (node
->CountChildren() == 1 && node
->ChildAt(0)->IsHidden()) {
2647 valueNode
= node
->ChildAt(0)->NodeChild()->Node();
2648 if (valueNode
!= NULL
&& valueNode
->IsRangedContainer())
2649 addRangedContainerItem
= true;
2652 if (addRangedContainerItem
) {
2653 result
= _AddContextAction("Set visible range" B_UTF8_ELLIPSIS
,
2654 MSG_SHOW_CONTAINER_RANGE_PROMPT
, _preActions
, message
);
2660 _postActions
= new(std::nothrow
) ContextActionList
;
2661 if (_postActions
== NULL
)
2664 BPrivate::ObjectDeleter
<ContextActionList
> postActionListDeleter(
2667 result
= _AddContextAction("Add watch expression" B_UTF8_ELLIPSIS
,
2668 MSG_ADD_WATCH_EXPRESSION
, _postActions
, message
);
2672 if (fExpressionChildren
.HasItem(node
->NodeChild())) {
2673 result
= _AddContextAction("Remove watch expression",
2674 MSG_REMOVE_WATCH_EXPRESSION
, _postActions
, message
);
2677 message
->AddPointer("node", node
);
2680 preActionListDeleter
.Detach();
2681 postActionListDeleter
.Detach();
2688 VariablesView::_AddContextAction(const char* action
, uint32 what
,
2689 ContextActionList
* actions
, BMessage
*& _message
)
2691 _message
= new(std::nothrow
) BMessage(what
);
2692 if (_message
== NULL
)
2695 ObjectDeleter
<BMessage
> messageDeleter(_message
);
2697 ActionMenuItem
* item
= new(std::nothrow
) ActionMenuItem(action
,
2702 messageDeleter
.Detach();
2703 ObjectDeleter
<ActionMenuItem
> actionDeleter(item
);
2704 if (!actions
->AddItem(item
))
2707 actionDeleter
.Detach();
2714 VariablesView::_FinishContextMenu(bool force
)
2716 if (fTableCellContextMenuTracker
!= NULL
) {
2717 if (!fTableCellContextMenuTracker
->FinishMenu(force
) || force
) {
2718 fTableCellContextMenuTracker
->ReleaseReference();
2719 fTableCellContextMenuTracker
= NULL
;
2727 VariablesView::_SaveViewState(bool updateValues
) const
2729 if (fThread
== NULL
|| fStackFrame
== NULL
2730 || fStackFrame
->Function() == NULL
) {
2734 // get the function ID
2735 FunctionID
* functionID
= fStackFrame
->Function()->GetFunctionID();
2736 if (functionID
== NULL
)
2738 BReference
<FunctionID
> functionIDReference(functionID
, true);
2740 StackFrameValues
* values
= NULL
;
2741 ExpressionValues
* expressionValues
= NULL
;
2742 BReference
<StackFrameValues
> valuesReference
;
2743 BReference
<ExpressionValues
> expressionsReference
;
2745 if (!updateValues
) {
2746 VariablesViewState
* viewState
= fViewStateHistory
->GetState(fThread
->ID(),
2748 if (viewState
!= NULL
) {
2749 values
= viewState
->Values();
2750 valuesReference
.SetTo(values
);
2752 expressionValues
= viewState
->GetExpressionValues();
2753 expressionsReference
.SetTo(expressionValues
);
2757 if (values
== NULL
) {
2758 values
= new(std::nothrow
) StackFrameValues
;
2761 valuesReference
.SetTo(values
, true);
2763 if (values
->Init() != B_OK
)
2766 expressionValues
= new(std::nothrow
) ExpressionValues
;
2767 if (expressionValues
== NULL
)
2769 expressionsReference
.SetTo(expressionValues
, true);
2771 if (expressionValues
->Init() != B_OK
)
2775 // create an empty view state
2776 VariablesViewState
* viewState
= new(std::nothrow
) VariablesViewState
;
2777 if (viewState
== NULL
)
2779 BReference
<VariablesViewState
> viewStateReference(viewState
, true);
2781 if (viewState
->Init() != B_OK
)
2784 viewState
->SetValues(values
);
2785 viewState
->SetExpressionValues(expressionValues
);
2789 if (_AddViewStateDescendentNodeInfos(viewState
,
2790 fVariableTableModel
->Root(), path
, updateValues
) != B_OK
) {
2794 // add the view state to the history
2795 fViewStateHistory
->SetState(fThread
->ID(), functionID
, viewState
);
2800 VariablesView::_RestoreViewState()
2802 if (fPreviousViewState
!= NULL
) {
2803 fPreviousViewState
->ReleaseReference();
2804 fPreviousViewState
= NULL
;
2807 if (fThread
== NULL
|| fStackFrame
== NULL
2808 || fStackFrame
->Function() == NULL
) {
2812 // get the function ID
2813 FunctionID
* functionID
= fStackFrame
->Function()->GetFunctionID();
2814 if (functionID
== NULL
)
2816 BReference
<FunctionID
> functionIDReference(functionID
, true);
2818 // get the previous view state
2819 VariablesViewState
* viewState
= fViewStateHistory
->GetState(fThread
->ID(),
2821 if (viewState
== NULL
)
2824 // apply the view state
2826 _ApplyViewStateDescendentNodeInfos(viewState
, fVariableTableModel
->Root(),
2832 VariablesView::_AddViewStateDescendentNodeInfos(VariablesViewState
* viewState
,
2833 void* parent
, TreeTablePath
& path
, bool updateValues
) const
2835 int32 childCount
= fVariableTableModel
->CountChildren(parent
);
2836 for (int32 i
= 0; i
< childCount
; i
++) {
2837 ModelNode
* node
= (ModelNode
*)fVariableTableModel
->ChildAt(parent
, i
);
2838 if (!path
.AddComponent(i
))
2841 // add the node's info
2842 VariablesViewNodeInfo nodeInfo
;
2843 nodeInfo
.SetNodeExpanded(fVariableTable
->IsNodeExpanded(path
));
2844 nodeInfo
.SetCastedType(node
->GetCastedType());
2845 TableCellValueRenderer
* renderer
= node
->TableCellRenderer();
2846 if (renderer
!= NULL
) {
2847 Settings
* settings
= renderer
->GetSettings();
2848 if (settings
!= NULL
)
2849 nodeInfo
.SetRendererSettings(settings
->Message());
2852 Value
* value
= node
->GetValue();
2853 Variable
* variable
= node
->GetVariable();
2854 TypeComponentPath
* componentPath
= node
->GetPath();
2855 ObjectID
* id
= variable
->ID();
2857 status_t error
= viewState
->SetNodeInfo(id
, componentPath
, nodeInfo
);
2861 if (value
!= NULL
&& updateValues
) {
2862 BVariant variableValueData
;
2863 if (value
->ToVariant(variableValueData
))
2864 error
= viewState
->Values()->SetValue(id
, componentPath
,
2871 error
= _AddViewStateDescendentNodeInfos(viewState
, node
, path
,
2876 path
.RemoveLastComponent();
2884 VariablesView::_ApplyViewStateDescendentNodeInfos(VariablesViewState
* viewState
,
2885 void* parent
, TreeTablePath
& path
)
2887 int32 childCount
= fVariableTableModel
->CountChildren(parent
);
2888 for (int32 i
= 0; i
< childCount
; i
++) {
2889 ModelNode
* node
= (ModelNode
*)fVariableTableModel
->ChildAt(parent
, i
);
2890 if (!path
.AddComponent(i
))
2893 // apply the node's info, if any
2894 ObjectID
* objectID
= node
->GetVariable()->ID();
2895 TypeComponentPath
* componentPath
= node
->GetPath();
2896 const VariablesViewNodeInfo
* nodeInfo
= viewState
->GetNodeInfo(
2897 objectID
, componentPath
);
2898 if (nodeInfo
!= NULL
) {
2899 // NB: if the node info indicates that the node in question
2900 // was being cast to a different type, this *must* be applied
2901 // before any other view state restoration, since it
2902 // potentially changes the child hierarchy under that node.
2903 Type
* type
= nodeInfo
->GetCastedType();
2905 ValueNode
* valueNode
= NULL
;
2906 if (TypeHandlerRoster::Default()->CreateValueNode(
2907 node
->NodeChild(), type
, valueNode
) == B_OK
) {
2908 node
->NodeChild()->SetNode(valueNode
);
2909 node
->SetCastedType(type
);
2913 // we don't have a renderer yet so we can't apply the settings
2914 // at this stage. Store them on the model node so we can lazily
2915 // apply them once the value is retrieved.
2916 node
->SetLastRendererSettings(nodeInfo
->GetRendererSettings());
2918 fVariableTable
->SetNodeExpanded(path
,
2919 nodeInfo
->IsNodeExpanded());
2921 BVariant previousValue
;
2922 if (viewState
->Values()->GetValue(objectID
, componentPath
,
2924 node
->SetPreviousValue(previousValue
);
2929 status_t error
= _ApplyViewStateDescendentNodeInfos(viewState
, node
,
2934 path
.RemoveLastComponent();
2942 VariablesView::_CopyVariableValueToClipboard()
2944 ModelNode
* node
= reinterpret_cast<ModelNode
*>(
2945 fVariableTable
->SelectionModel()->NodeAt(0));
2947 Value
* value
= node
->GetValue();
2949 if (value
!= NULL
&& value
->ToString(valueData
)) {
2950 be_clipboard
->Lock();
2951 be_clipboard
->Data()->RemoveData("text/plain");
2952 be_clipboard
->Data()->AddData ("text/plain",
2953 B_MIME_TYPE
, valueData
.String(),
2954 valueData
.Length());
2955 be_clipboard
->Commit();
2956 be_clipboard
->Unlock();
2962 VariablesView::_AddExpression(const char* expression
,
2963 bool persistentExpression
, ExpressionInfo
*& _info
)
2965 ExpressionInfoEntry
* entry
= NULL
;
2966 if (persistentExpression
) {
2967 // if our stack frame doesn't have an associated function,
2968 // we can't add an expression
2969 FunctionInstance
* function
= fStackFrame
->Function();
2970 if (function
== NULL
)
2971 return B_NOT_ALLOWED
;
2973 FunctionID
* id
= function
->GetFunctionID();
2977 BReference
<FunctionID
> idReference(id
, true);
2979 entry
= fExpressions
->Lookup(FunctionKey(id
));
2980 if (entry
== NULL
) {
2981 entry
= new(std::nothrow
) ExpressionInfoEntry(id
);
2984 status_t error
= fExpressions
->Insert(entry
);
2985 if (error
!= B_OK
) {
2992 ExpressionInfo
* info
= new(std::nothrow
) ExpressionInfo(expression
);
2997 BReference
<ExpressionInfo
> infoReference(info
, true);
2999 if (persistentExpression
) {
3000 if (!entry
->AddItem(info
))
3003 fTemporaryExpression
= info
;
3005 info
->AddListener(this);
3006 infoReference
.Detach();
3013 VariablesView::_RemoveExpression(ModelNode
* node
)
3015 if (!fExpressionChildren
.HasItem(node
->NodeChild()))
3018 FunctionID
* id
= fStackFrame
->Function()->GetFunctionID();
3019 BReference
<FunctionID
> idReference(id
, true);
3021 ExpressionInfoEntry
* entry
= fExpressions
->Lookup(FunctionKey(id
));
3025 for (int32 i
= 0; i
< entry
->CountItems(); i
++) {
3026 ExpressionInfo
* info
= entry
->ItemAt(i
);
3027 if (info
->Expression() == node
->Name()) {
3028 entry
->RemoveItemAt(i
);
3029 info
->RemoveListener(this);
3030 info
->ReleaseReference();
3035 fVariableTableModel
->RemoveSyntheticNode(node
);
3040 VariablesView::_RestoreExpressionNodes()
3042 FunctionInstance
* instance
= fStackFrame
->Function();
3043 if (instance
== NULL
)
3046 FunctionID
* id
= instance
->GetFunctionID();
3050 BReference
<FunctionID
> idReference(id
, true);
3052 ExpressionInfoEntry
* entry
= fExpressions
->Lookup(FunctionKey(id
));
3056 for (int32 i
= 0; i
< entry
->CountItems(); i
++) {
3057 ExpressionInfo
* info
= entry
->ItemAt(i
);
3058 fListener
->ExpressionEvaluationRequested(info
, fStackFrame
, fThread
);
3064 VariablesView::_AddExpressionNode(ExpressionInfo
* info
, status_t result
,
3065 ExpressionResult
* value
)
3067 bool temporaryExpression
= (info
== fTemporaryExpression
);
3068 Variable
* variable
= NULL
;
3069 BReference
<Variable
> variableReference
;
3072 ExpressionVariableID
* id
3073 = new(std::nothrow
) ExpressionVariableID(info
);
3076 BReference
<ObjectID
> idReference(id
, true);
3079 ValueLocation
* location
= NULL
;
3080 ValueNodeChild
* child
= NULL
;
3081 BReference
<Type
> typeReference
;
3082 BReference
<ValueLocation
> locationReference
;
3083 if (value
->Kind() == EXPRESSION_RESULT_KIND_PRIMITIVE
) {
3084 value
->PrimitiveValue()->ToVariant(valueData
);
3085 if (_GetTypeForTypeCode(valueData
.Type(), type
) != B_OK
)
3087 typeReference
.SetTo(type
, true);
3089 location
= new(std::nothrow
) ValueLocation();
3090 if (location
== NULL
)
3092 locationReference
.SetTo(location
, true);
3094 if (valueData
.IsNumber()) {
3096 ValuePieceLocation piece
;
3097 if (!piece
.SetToValue(valueData
.Bytes(), valueData
.Size())
3098 || !location
->AddPiece(piece
)) {
3102 } else if (value
->Kind() == EXPRESSION_RESULT_KIND_VALUE_NODE
) {
3103 child
= value
->ValueNodeValue();
3104 type
= child
->GetType();
3105 typeReference
.SetTo(type
);
3106 location
= child
->Location();
3107 locationReference
.SetTo(location
);
3110 variable
= new(std::nothrow
) Variable(id
,
3111 info
->Expression(), type
, location
);
3112 if (variable
== NULL
)
3114 variableReference
.SetTo(variable
, true);
3116 status_t error
= fVariableTableModel
->AddSyntheticNode(variable
, child
,
3117 info
->Expression());
3121 // In the case of either an evaluation error, or an unsupported result
3122 // type, set an explanatory string for the result directly.
3123 if (result
!= B_OK
|| valueData
.Type() == B_STRING_TYPE
) {
3124 StringValue
* explicitValue
= new(std::nothrow
) StringValue(
3125 valueData
.ToString());
3126 if (explicitValue
== NULL
)
3129 child
->Node()->SetLocationAndValue(NULL
, explicitValue
, B_OK
);
3132 if (temporaryExpression
|| fExpressionChildren
.AddItem(child
)) {
3133 child
->AcquireReference();
3135 if (temporaryExpression
)
3138 // attempt to restore our newly added node's view state,
3140 FunctionID
* functionID
= fStackFrame
->Function()
3142 if (functionID
== NULL
)
3144 BReference
<FunctionID
> functionIDReference(functionID
,
3146 VariablesViewState
* viewState
= fViewStateHistory
3147 ->GetState(fThread
->ID(), functionID
);
3148 if (viewState
!= NULL
) {
3150 _ApplyViewStateDescendentNodeInfos(viewState
,
3151 fVariableTableModel
->Root(), path
);
3158 VariablesView::_HandleTypecastResult(status_t result
, ExpressionResult
* value
)
3160 BString errorMessage
;
3161 if (value
== NULL
) {
3162 errorMessage
.SetToFormat("Failed to evaluate expression \"%s\": %s (%"
3163 B_PRId32
")", fPendingTypecastInfo
->Expression().String(),
3164 strerror(result
), result
);
3165 } else if (result
!= B_OK
) {
3167 value
->PrimitiveValue()->ToVariant(valueData
);
3169 // usually, the evaluation can give us back an error message to
3170 // specifically indicate why it failed. If it did, simply use
3171 // the message directly, otherwise fall back to generating an error
3172 // message based on the error code
3173 if (valueData
.Type() == B_STRING_TYPE
)
3174 errorMessage
= valueData
.ToString();
3176 errorMessage
.SetToFormat("Failed to evaluate expression \"%s\":"
3177 " %s (%" B_PRId32
")",
3178 fPendingTypecastInfo
->Expression().String(), strerror(result
),
3182 } else if (value
->Kind() != EXPRESSION_RESULT_KIND_TYPE
) {
3183 errorMessage
.SetToFormat("Expression \"%s\" does not evaluate to a"
3184 " type.", fPendingTypecastInfo
->Expression().String());
3187 if (!errorMessage
.IsEmpty()) {
3188 BAlert
* alert
= new(std::nothrow
) BAlert("Typecast error",
3189 errorMessage
, "Close");
3196 Type
* type
= value
->GetType();
3197 BReference
<Type
> typeRef(type
);
3198 ValueNode
* valueNode
= NULL
;
3199 ModelNode
* node
= fPendingTypecastInfo
->TargetNode();
3200 if (TypeHandlerRoster::Default()->CreateValueNode(node
->NodeChild(), type
,
3201 valueNode
) != B_OK
) {
3205 node
->NodeChild()->SetNode(valueNode
);
3206 node
->SetCastedType(type
);
3207 fVariableTableModel
->NotifyNodeChanged(node
);
3212 VariablesView::_HandleEditVariableRequest(ModelNode
* node
, Value
* value
)
3214 // get a value handler
3215 ValueHandler
* valueHandler
;
3216 status_t error
= ValueHandlerRoster::Default()->FindValueHandler(value
,
3221 ValueNode
* valueNode
= node
->NodeChild()->Node();
3223 BReference
<ValueHandler
> handlerReference(valueHandler
, true);
3224 TableCellValueRenderer
* renderer
= node
->TableCellRenderer();
3225 TableCellValueEditor
* editor
= NULL
;
3226 error
= valueHandler
->GetTableCellValueEditor(value
,
3227 renderer
!= NULL
? renderer
->GetSettings() : NULL
, editor
);
3228 if (error
!= B_OK
|| editor
== NULL
)
3231 BReference
<TableCellValueEditor
> editorReference(editor
, true);
3234 fEditWindow
= VariableEditWindow::Create(value
, valueNode
, editor
,
3241 fEditWindow
->Show();
3246 VariablesView::_GetTypeForTypeCode(int32 type
, Type
*& _resultType
) const
3248 if (BVariant::TypeIsNumber(type
) || type
== B_STRING_TYPE
) {
3249 _resultType
= new(std::nothrow
) SyntheticPrimitiveType(type
);
3250 if (_resultType
== NULL
)
3256 return B_NOT_SUPPORTED
;
3260 // #pragma mark - Listener
3263 VariablesView::Listener::~Listener()