1/*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2011-2018, Rene Gollent, rene@gollent.com.
4 * Distributed under the terms of the MIT License.
5 */
6
7
8#include "VariablesView.h"
9
10#include <new>
11
12#include <debugger.h>
13
14#include <Alert.h>
15#include <Clipboard.h>
16#include <ControlLook.h>
17#include <Looper.h>
18#include <PopUpMenu.h>
19#include <ToolTip.h>
20
21#include <AutoDeleter.h>
22#include <AutoLocker.h>
23#include <PromptWindow.h>
24
25#include "table/TableColumns.h"
26
27#include "ActionMenuItem.h"
28#include "AppMessageCodes.h"
29#include "Architecture.h"
30#include "ExpressionInfo.h"
31#include "ExpressionValues.h"
32#include "FileSourceCode.h"
33#include "Function.h"
34#include "FunctionID.h"
35#include "FunctionInstance.h"
36#include "GuiSettingsUtils.h"
37#include "MessageCodes.h"
38#include "RangeList.h"
39#include "Register.h"
40#include "SettingsMenu.h"
41#include "SourceLanguage.h"
42#include "StackTrace.h"
43#include "StackFrame.h"
44#include "StackFrameValues.h"
45#include "StringUtils.h"
46#include "StringValue.h"
47#include "SyntheticPrimitiveType.h"
48#include "TableCellValueEditor.h"
49#include "TableCellValueRenderer.h"
50#include "Team.h"
51#include "TeamDebugInfo.h"
52#include "Thread.h"
53#include "Tracing.h"
54#include "TypeComponentPath.h"
55#include "TypeHandler.h"
56#include "TypeHandlerMenuItem.h"
57#include "TypeHandlerRoster.h"
58#include "TypeLookupConstraints.h"
59#include "UiUtils.h"
60#include "Value.h"
61#include "ValueHandler.h"
62#include "ValueHandlerRoster.h"
63#include "ValueLocation.h"
64#include "ValueNode.h"
65#include "ValueNodeManager.h"
66#include "Variable.h"
67#include "VariableEditWindow.h"
68#include "VariableValueNodeChild.h"
69#include "VariablesViewState.h"
70#include "VariablesViewStateHistory.h"
71
72
73enum {
74	VALUE_NODE_TYPE	= 'valn'
75};
76
77
78enum {
79	MSG_MODEL_NODE_HIDDEN			= 'monh',
80	MSG_VALUE_NODE_NEEDS_VALUE		= 'mvnv',
81	MSG_RESTORE_PARTIAL_VIEW_STATE	= 'mpvs',
82	MSG_ADD_WATCH_EXPRESSION		= 'awex',
83	MSG_REMOVE_WATCH_EXPRESSION		= 'rwex',
84	MSG_USE_AUTOMATIC_HANDLER		= 'uaha',
85	MSG_USE_EXPLICIT_HANDLER		= 'ueha'
86};
87
88
89// maximum number of array elements to show by default
90static const uint64 kMaxArrayElementCount = 10;
91
92
93// #pragma mark - FunctionKey
94
95
96struct VariablesView::FunctionKey {
97	FunctionID*			function;
98
99	FunctionKey(FunctionID* function)
100		:
101		function(function)
102	{
103	}
104
105	uint32 HashValue() const
106	{
107		return function->HashValue();
108	}
109
110	bool operator==(const FunctionKey& other) const
111	{
112		return *function == *other.function;
113	}
114};
115
116
117// #pragma mark - ExpressionInfoEntry
118
119
120struct VariablesView::ExpressionInfoEntry : FunctionKey, ExpressionInfoList {
121	ExpressionInfoEntry* next;
122
123	ExpressionInfoEntry(FunctionID* function)
124		:
125		FunctionKey(function),
126		ExpressionInfoList(10, false)
127	{
128		function->AcquireReference();
129	}
130
131	~ExpressionInfoEntry()
132	{
133		_Cleanup();
134	}
135
136	void SetInfo(const ExpressionInfoList& infoList)
137	{
138		_Cleanup();
139
140		for (int32 i = 0; i < infoList.CountItems(); i++) {
141			ExpressionInfo* info = infoList.ItemAt(i);
142			if (!AddItem(info))
143				break;
144
145			info->AcquireReference();
146		}
147	}
148
149private:
150	void _Cleanup()
151	{
152		for (int32 i = 0; i < CountItems(); i++)
153			ItemAt(i)->ReleaseReference();
154
155		MakeEmpty();
156	}
157};
158
159
160// #pragma mark - ExpressionInfoEntryHashDefinition
161
162
163struct VariablesView::ExpressionInfoEntryHashDefinition {
164	typedef FunctionKey		KeyType;
165	typedef	ExpressionInfoEntry	ValueType;
166
167	size_t HashKey(const FunctionKey& key) const
168	{
169		return key.HashValue();
170	}
171
172	size_t Hash(const ExpressionInfoEntry* value) const
173	{
174		return value->HashValue();
175	}
176
177	bool Compare(const FunctionKey& key,
178		const ExpressionInfoEntry* value) const
179	{
180		return key == *value;
181	}
182
183	ExpressionInfoEntry*& GetLink(ExpressionInfoEntry* value) const
184	{
185		return value->next;
186	}
187};
188
189
190// #pragma mark - ContainerListener
191
192
193class VariablesView::ContainerListener : public ValueNodeContainer::Listener {
194public:
195								ContainerListener(BHandler* indirectTarget);
196
197			void				SetModel(VariableTableModel* model);
198
199	virtual	void				ValueNodeChanged(ValueNodeChild* nodeChild,
200									ValueNode* oldNode, ValueNode* newNode);
201	virtual	void				ValueNodeChildrenCreated(ValueNode* node);
202	virtual	void				ValueNodeChildrenDeleted(ValueNode* node);
203	virtual	void				ValueNodeValueChanged(ValueNode* node);
204
205	virtual void				ModelNodeHidden(ModelNode* node);
206
207	virtual void				ModelNodeValueRequested(ModelNode* node);
208
209	virtual void				ModelNodeRestoreViewStateRequested(ModelNode* node);
210
211private:
212			BHandler*			fIndirectTarget;
213			VariableTableModel*	fModel;
214};
215
216
217// #pragma mark - ExpressionVariableID
218
219
220class VariablesView::ExpressionVariableID : public ObjectID {
221public:
222	ExpressionVariableID(ExpressionInfo* info)
223		:
224		fInfo(info)
225	{
226		fInfo->AcquireReference();
227	}
228
229	virtual ~ExpressionVariableID()
230	{
231		fInfo->ReleaseReference();
232	}
233
234	virtual	bool operator==(const ObjectID& other) const
235	{
236		const ExpressionVariableID* otherID
237			= dynamic_cast<const ExpressionVariableID*>(&other);
238		if (otherID == NULL)
239			return false;
240
241		return fInfo == otherID->fInfo;
242	}
243
244protected:
245	virtual	uint32 ComputeHashValue() const
246	{
247		uint32 hash = reinterpret_cast<addr_t>(fInfo);
248		hash = hash * 19 + StringUtils::HashValue(fInfo->Expression());
249
250		return hash;
251	}
252
253private:
254	ExpressionInfo*	fInfo;
255};
256
257
258// #pragma mark - ModelNode
259
260
261class VariablesView::ModelNode : public BReferenceable {
262public:
263	ModelNode(ModelNode* parent, Variable* variable, ValueNodeChild* nodeChild,
264		bool isPresentationNode)
265		:
266		fParent(parent),
267		fNodeChild(nodeChild),
268		fVariable(variable),
269		fValue(NULL),
270		fPreviousValue(),
271		fValueHandler(NULL),
272		fTableCellRenderer(NULL),
273		fLastRendererSettings(),
274		fCastedType(NULL),
275		fTypeHandler(NULL),
276		fComponentPath(NULL),
277		fIsPresentationNode(isPresentationNode),
278		fHidden(false),
279		fValueChanged(false),
280		fPresentationName()
281	{
282		fVariable->AcquireReference();
283		fNodeChild->AcquireReference();
284	}
285
286	~ModelNode()
287	{
288		SetTableCellRenderer(NULL);
289		SetValueHandler(NULL);
290		SetValue(NULL);
291
292		for (int32 i = 0; ModelNode* child = fChildren.ItemAt(i); i++)
293			child->ReleaseReference();
294
295		fNodeChild->ReleaseReference();
296		fVariable->ReleaseReference();
297
298		if (fComponentPath != NULL)
299			fComponentPath->ReleaseReference();
300
301		if (fCastedType != NULL)
302			fCastedType->ReleaseReference();
303
304		if (fTypeHandler != NULL)
305			fTypeHandler->ReleaseReference();
306	}
307
308	status_t Init()
309	{
310		fComponentPath = new(std::nothrow) TypeComponentPath();
311		if (fComponentPath == NULL)
312			return B_NO_MEMORY;
313
314		if (fParent != NULL)
315			*fComponentPath = *fParent->GetPath();
316
317		TypeComponent component;
318		// TODO: this should actually discriminate between different
319		// classes of type component kinds
320		component.SetToBaseType(fNodeChild->GetType()->Kind(),
321			0, fNodeChild->Name());
322
323		fComponentPath->AddComponent(component);
324
325		return B_OK;
326	}
327
328	ModelNode* Parent() const
329	{
330		return fParent;
331	}
332
333	ValueNodeChild* NodeChild() const
334	{
335		return fNodeChild;
336	}
337
338	const BString& Name() const
339	{
340		return fPresentationName.IsEmpty()
341			? fNodeChild->Name() : fPresentationName;
342	}
343
344	void SetPresentationName(const BString& name)
345	{
346		fPresentationName = name;
347	}
348
349	Type* GetType() const
350	{
351		if (fCastedType != NULL)
352			return fCastedType;
353
354		return fNodeChild->GetType();
355	}
356
357	Variable* GetVariable() const
358	{
359		return fVariable;
360	}
361
362	Value* GetValue() const
363	{
364		return fValue;
365	}
366
367	void SetValue(Value* value)
368	{
369		if (value == fValue)
370			return;
371
372		if (fValue != NULL)
373			fValue->ReleaseReference();
374
375		fValue = value;
376
377		if (fValue != NULL)
378			fValue->AcquireReference();
379
380		_CompareValues();
381	}
382
383	const BVariant& PreviousValue() const
384	{
385		return fPreviousValue;
386	}
387
388	void SetPreviousValue(const BVariant& value)
389	{
390		fPreviousValue = value;
391	}
392
393	Type* GetCastedType() const
394	{
395		return fCastedType;
396	}
397
398	void SetCastedType(Type* type)
399	{
400		if (fCastedType != NULL)
401			fCastedType->ReleaseReference();
402
403		fCastedType = type;
404		if (type != NULL)
405			fCastedType->AcquireReference();
406	}
407
408	TypeHandler* GetTypeHandler() const
409	{
410		return fTypeHandler;
411	}
412
413	void SetTypeHandler(TypeHandler* handler)
414	{
415		if (fTypeHandler != NULL)
416			fTypeHandler->ReleaseReference();
417
418		fTypeHandler = handler;
419		if (fTypeHandler != NULL)
420			fTypeHandler->AcquireReference();
421	}
422
423
424	const BMessage& GetLastRendererSettings() const
425	{
426		return fLastRendererSettings;
427	}
428
429	void SetLastRendererSettings(const BMessage& settings)
430	{
431		fLastRendererSettings = settings;
432	}
433
434	TypeComponentPath* GetPath() const
435	{
436		return fComponentPath;
437	}
438
439	ValueHandler* GetValueHandler() const
440	{
441		return fValueHandler;
442	}
443
444	void SetValueHandler(ValueHandler* handler)
445	{
446		if (handler == fValueHandler)
447			return;
448
449		if (fValueHandler != NULL)
450			fValueHandler->ReleaseReference();
451
452		fValueHandler = handler;
453
454		if (fValueHandler != NULL)
455			fValueHandler->AcquireReference();
456	}
457
458
459	TableCellValueRenderer* TableCellRenderer() const
460	{
461		return fTableCellRenderer;
462	}
463
464	void SetTableCellRenderer(TableCellValueRenderer* renderer)
465	{
466		if (renderer == fTableCellRenderer)
467			return;
468
469		if (fTableCellRenderer != NULL)
470			fTableCellRenderer->ReleaseReference();
471
472		fTableCellRenderer = renderer;
473
474		if (fTableCellRenderer != NULL)
475			fTableCellRenderer->AcquireReference();
476	}
477
478	bool IsPresentationNode() const
479	{
480		return fIsPresentationNode;
481	}
482
483	bool IsHidden() const
484	{
485		return fHidden;
486	}
487
488	void SetHidden(bool hidden)
489	{
490		fHidden = hidden;
491	}
492
493	bool ValueChanged() const
494	{
495		return fValueChanged;
496	}
497
498	int32 CountChildren() const
499	{
500		return fChildren.CountItems();
501	}
502
503	ModelNode* ChildAt(int32 index) const
504	{
505		return fChildren.ItemAt(index);
506	}
507
508	int32 IndexOf(ModelNode* child) const
509	{
510		return fChildren.IndexOf(child);
511	}
512
513	bool AddChild(ModelNode* child)
514	{
515		if (!fChildren.AddItem(child))
516			return false;
517
518		child->AcquireReference();
519		return true;
520	}
521
522	bool RemoveChild(ModelNode* child)
523	{
524		if (!fChildren.RemoveItem(child))
525			return false;
526
527		child->ReleaseReference();
528		return true;
529	}
530
531	bool RemoveAllChildren()
532	{
533		for (int32 i = 0; i < fChildren.CountItems(); i++)
534			RemoveChild(fChildren.ItemAt(i));
535
536		return true;
537	}
538
539private:
540	typedef BObjectList<ModelNode> ChildList;
541
542private:
543	void _CompareValues()
544	{
545		fValueChanged = false;
546		if (fValue != NULL) {
547			if (fPreviousValue.Type() != 0) {
548				BVariant newValue;
549				fValue->ToVariant(newValue);
550				fValueChanged = (fPreviousValue != newValue);
551			} else {
552				// for expression variables, always consider the initial
553				// value as changed, since their evaluation has just been
554				// requested, and thus their initial value is by definition
555				// new/of interest
556				fValueChanged = dynamic_cast<ExpressionVariableID*>(
557					fVariable->ID()) != NULL;
558			}
559		}
560	}
561
562private:
563	ModelNode*				fParent;
564	ValueNodeChild*			fNodeChild;
565	Variable*				fVariable;
566	Value*					fValue;
567	BVariant				fPreviousValue;
568	ValueHandler*			fValueHandler;
569	TableCellValueRenderer*	fTableCellRenderer;
570	BMessage				fLastRendererSettings;
571	Type*					fCastedType;
572	TypeHandler*			fTypeHandler;
573	ChildList				fChildren;
574	TypeComponentPath*		fComponentPath;
575	bool					fIsPresentationNode;
576	bool					fHidden;
577	bool					fValueChanged;
578	BString					fPresentationName;
579
580public:
581	ModelNode*				fNext;
582};
583
584
585// #pragma mark - VariablesExpressionInfo
586
587
588class VariablesView::VariablesExpressionInfo : public ExpressionInfo {
589public:
590	VariablesExpressionInfo(const BString& expression, ModelNode* node)
591		:
592		ExpressionInfo(expression),
593		fTargetNode(node)
594	{
595		fTargetNode->AcquireReference();
596	}
597
598	virtual ~VariablesExpressionInfo()
599	{
600		fTargetNode->ReleaseReference();
601	}
602
603	inline ModelNode* TargetNode() const
604	{
605		return fTargetNode;
606	}
607
608private:
609	ModelNode* fTargetNode;
610};
611
612
613// #pragma mark - VariableValueColumn
614
615
616class VariablesView::VariableValueColumn : public StringTableColumn {
617public:
618	VariableValueColumn(int32 modelIndex, const char* title, float width,
619		float minWidth, float maxWidth, uint32 truncate = B_TRUNCATE_MIDDLE,
620		alignment align = B_ALIGN_RIGHT)
621		:
622		StringTableColumn(modelIndex, title, width, minWidth, maxWidth,
623			truncate, align)
624	{
625	}
626
627protected:
628	void DrawValue(const BVariant& value, BRect rect, BView* targetView)
629	{
630		// draw the node's value with the designated renderer
631		if (value.Type() == VALUE_NODE_TYPE) {
632			ModelNode* node = dynamic_cast<ModelNode*>(value.ToReferenceable());
633			if (node != NULL && node->GetValue() != NULL
634				&& node->TableCellRenderer() != NULL) {
635				node->TableCellRenderer()->RenderValue(node->GetValue(),
636					node->ValueChanged(), rect, targetView);
637				return;
638			}
639		} else if (value.Type() == B_STRING_TYPE) {
640			fField.SetString(value.ToString());
641		} else {
642			// fall back to drawing an empty string
643			fField.SetString("");
644		}
645		fField.SetWidth(Width());
646		fColumn.DrawField(&fField, rect, targetView);
647	}
648
649	float GetPreferredWidth(const BVariant& value, BView* targetView) const
650	{
651		// get the preferred width from the node's designated renderer
652		if (value.Type() == VALUE_NODE_TYPE) {
653			ModelNode* node = dynamic_cast<ModelNode*>(value.ToReferenceable());
654			if (node != NULL && node->GetValue() != NULL
655				&& node->TableCellRenderer() != NULL) {
656				return node->TableCellRenderer()->PreferredValueWidth(
657					node->GetValue(), targetView);
658			}
659		}
660
661		return fColumn.BTitledColumn::GetPreferredWidth(NULL, targetView);
662	}
663
664	virtual BField* PrepareField(const BVariant& _value) const
665	{
666		return NULL;
667	}
668};
669
670
671// #pragma mark - VariableTableModel
672
673
674class VariablesView::VariableTableModel : public TreeTableModel,
675	public TreeTableToolTipProvider {
676public:
677								VariableTableModel(ValueNodeManager* manager);
678								~VariableTableModel();
679
680			status_t			Init();
681
682			void				SetContainerListener(
683									ContainerListener* listener);
684
685			void				SetStackFrame(::Thread* thread,
686									StackFrame* stackFrame);
687
688			void				ValueNodeChanged(ValueNodeChild* nodeChild,
689									ValueNode* oldNode, ValueNode* newNode);
690			void				ValueNodeChildrenCreated(ValueNode* node);
691			void				ValueNodeChildrenDeleted(ValueNode* node);
692			void				ValueNodeValueChanged(ValueNode* node);
693
694	virtual	int32				CountColumns() const;
695	virtual	void*				Root() const;
696	virtual	int32				CountChildren(void* parent) const;
697	virtual	void*				ChildAt(void* parent, int32 index) const;
698	virtual	bool				GetValueAt(void* object, int32 columnIndex,
699									BVariant& _value);
700
701			bool				GetTreePath(ModelNode* node,
702									TreeTablePath& _path) const;
703
704			void				NodeExpanded(ModelNode* node);
705
706			void				NotifyNodeChanged(ModelNode* node);
707			void				NotifyNodeHidden(ModelNode* node);
708
709	virtual	bool				GetToolTipForTablePath(
710									const TreeTablePath& path,
711									int32 columnIndex, BToolTip** _tip);
712
713			status_t			AddSyntheticNode(Variable* variable,
714									ValueNodeChild*& _child,
715									const char* presentationName = NULL);
716			void				RemoveSyntheticNode(ModelNode* node);
717
718private:
719			struct NodeHashDefinition {
720				typedef ValueNodeChild*	KeyType;
721				typedef	ModelNode		ValueType;
722
723				size_t HashKey(const ValueNodeChild* key) const
724				{
725					return (size_t)key;
726				}
727
728				size_t Hash(const ModelNode* value) const
729				{
730					return HashKey(value->NodeChild());
731				}
732
733				bool Compare(const ValueNodeChild* key,
734					const ModelNode* value) const
735				{
736					return value->NodeChild() == key;
737				}
738
739				ModelNode*& GetLink(ModelNode* value) const
740				{
741					return value->fNext;
742				}
743			};
744
745			typedef BObjectList<ModelNode> NodeList;
746			typedef BOpenHashTable<NodeHashDefinition> NodeTable;
747
748private:
749			// container must be locked
750
751			status_t			_AddNode(Variable* variable, ModelNode* parent,
752									ValueNodeChild* nodeChild,
753									bool isPresentationNode = false,
754									bool isOnlyChild = false);
755
756private:
757			::Thread*			fThread;
758			ValueNodeManager*	fNodeManager;
759			ContainerListener*	fContainerListener;
760			NodeList			fNodes;
761			NodeTable			fNodeTable;
762};
763
764
765class VariablesView::ContextMenu : public BPopUpMenu {
766public:
767	ContextMenu(const BMessenger& parent, const char* name)
768		: BPopUpMenu(name, false, false),
769		  fParent(parent)
770	{
771	}
772
773	virtual void Hide()
774	{
775		BPopUpMenu::Hide();
776
777		BMessage message(MSG_VARIABLES_VIEW_CONTEXT_MENU_DONE);
778		message.AddPointer("menu", this);
779		fParent.SendMessage(&message);
780	}
781
782private:
783	BMessenger	fParent;
784};
785
786
787// #pragma mark - TableCellContextMenuTracker
788
789
790class VariablesView::TableCellContextMenuTracker : public BReferenceable,
791	Settings::Listener {
792public:
793	TableCellContextMenuTracker(ModelNode* node, BLooper* parentLooper,
794		const BMessenger& parent)
795		:
796		fNode(node),
797		fParentLooper(parentLooper),
798		fParent(parent),
799		fRendererSettings(NULL),
800		fRendererSettingsMenu(NULL),
801		fRendererMenuAdded(false),
802		fMenuPreparedToShow(false)
803	{
804		fNode->AcquireReference();
805	}
806
807	~TableCellContextMenuTracker()
808	{
809		FinishMenu(true);
810
811		if (fRendererSettingsMenu != NULL)
812			fRendererSettingsMenu->ReleaseReference();
813
814		if (fRendererSettings != NULL)
815			fRendererSettings->ReleaseReference();
816
817		fNode->ReleaseReference();
818	}
819
820	status_t Init(Settings* rendererSettings,
821		SettingsMenu* rendererSettingsMenu,
822		ContextActionList* preSettingsActions = NULL,
823		ContextActionList* postSettingsActions = NULL)
824	{
825		if (rendererSettings == NULL && preSettingsActions == NULL
826			&& postSettingsActions == NULL) {
827			return B_BAD_VALUE;
828		}
829
830		if (rendererSettings != NULL) {
831			fRendererSettings = rendererSettings;
832			fRendererSettings->AcquireReference();
833
834
835			fRendererSettingsMenu = rendererSettingsMenu;
836			fRendererSettingsMenu->AcquireReference();
837		}
838
839		fContextMenu = new(std::nothrow) ContextMenu(fParent,
840			"table cell settings popup");
841		if (fContextMenu == NULL)
842			return B_NO_MEMORY;
843
844		status_t error = B_OK;
845		if (preSettingsActions != NULL
846			&& preSettingsActions->CountItems() > 0) {
847			error = _AddActionItems(preSettingsActions);
848			if (error != B_OK)
849				return error;
850
851			if (fRendererSettingsMenu != NULL || postSettingsActions != NULL)
852				fContextMenu->AddSeparatorItem();
853		}
854
855		if (fRendererSettingsMenu != NULL) {
856			error = fRendererSettingsMenu->AddToMenu(fContextMenu,
857				fContextMenu->CountItems());
858			if (error != B_OK)
859				return error;
860
861			if (postSettingsActions != NULL)
862				fContextMenu->AddSeparatorItem();
863		}
864
865		if (postSettingsActions != NULL) {
866			error = _AddActionItems(postSettingsActions);
867			if (error != B_OK)
868				return error;
869
870		}
871
872		if (fRendererSettings != NULL) {
873			AutoLocker<Settings> settingsLocker(fRendererSettings);
874			fRendererSettings->AddListener(this);
875			fRendererMenuAdded = true;
876		}
877
878		return B_OK;
879	}
880
881	void ShowMenu(BPoint screenWhere)
882	{
883		if (fRendererMenuAdded)
884			fRendererSettingsMenu->PrepareToShow(fParentLooper);
885
886		for (int32 i = 0; i < fContextMenu->CountItems(); i++) {
887			ActionMenuItem* item = dynamic_cast<ActionMenuItem*>(
888				fContextMenu->ItemAt(i));
889			if (item != NULL)
890				item->PrepareToShow(fParentLooper, fParent.Target(NULL));
891		}
892
893		fMenuPreparedToShow = true;
894
895		BRect mouseRect(screenWhere, screenWhere);
896		mouseRect.InsetBy(-4.0, -4.0);
897		fContextMenu->Go(screenWhere, true, false, mouseRect, true);
898	}
899
900	bool FinishMenu(bool force)
901	{
902		bool stillActive = false;
903
904		if (fMenuPreparedToShow) {
905			if (fRendererMenuAdded)
906				stillActive = fRendererSettingsMenu->Finish(fParentLooper,
907					force);
908			for (int32 i = 0; i < fContextMenu->CountItems(); i++) {
909				ActionMenuItem* item = dynamic_cast<ActionMenuItem*>(
910					fContextMenu->ItemAt(i));
911				if (item != NULL) {
912					stillActive |= item->Finish(fParentLooper,
913						fParent.Target(NULL), force);
914				}
915			}
916
917			fMenuPreparedToShow = stillActive;
918		}
919
920		if (fRendererMenuAdded) {
921			fRendererSettingsMenu->RemoveFromMenu();
922			fRendererSettings->RemoveListener(this);
923			fRendererMenuAdded = false;
924		}
925
926		if (fContextMenu != NULL) {
927			delete fContextMenu;
928			fContextMenu = NULL;
929		}
930
931		return stillActive;
932	}
933
934private:
935	// Settings::Listener
936
937	virtual void SettingValueChanged(Setting* setting)
938	{
939		BMessage message(MSG_VARIABLES_VIEW_NODE_SETTINGS_CHANGED);
940		fNode->AcquireReference();
941		if (message.AddPointer("node", fNode) != B_OK
942			|| fParent.SendMessage(&message) != B_OK) {
943			fNode->ReleaseReference();
944		}
945	}
946
947	status_t _AddActionItems(ContextActionList* actions)
948	{
949		if (fContextMenu == NULL)
950			return B_BAD_VALUE;
951
952		int32 index = fContextMenu->CountItems();
953		for (int32 i = 0; ActionMenuItem* item = actions->ItemAt(i); i++) {
954			if (!fContextMenu->AddItem(item, index + i)) {
955				for (i--; i >= 0; i--)
956					fContextMenu->RemoveItem(fContextMenu->ItemAt(index + i));
957
958				return B_NO_MEMORY;
959			}
960		}
961
962		return B_OK;
963	}
964
965private:
966	ModelNode*		fNode;
967	BLooper*		fParentLooper;
968	BMessenger		fParent;
969	ContextMenu*	fContextMenu;
970	Settings*		fRendererSettings;
971	SettingsMenu*	fRendererSettingsMenu;
972	bool			fRendererMenuAdded;
973	bool			fMenuPreparedToShow;
974};
975
976
977// #pragma mark - ContainerListener
978
979
980VariablesView::ContainerListener::ContainerListener(BHandler* indirectTarget)
981	:
982	fIndirectTarget(indirectTarget),
983	fModel(NULL)
984{
985}
986
987
988void
989VariablesView::ContainerListener::SetModel(VariableTableModel* model)
990{
991	fModel = model;
992}
993
994
995void
996VariablesView::ContainerListener::ValueNodeChanged(ValueNodeChild* nodeChild,
997	ValueNode* oldNode, ValueNode* newNode)
998{
999	// If the looper is already locked, invoke the model's hook synchronously.
1000	if (fIndirectTarget->Looper()->IsLocked()) {
1001		fModel->ValueNodeChanged(nodeChild, oldNode, newNode);
1002		return;
1003	}
1004
1005	// looper not locked yet -- call asynchronously to avoid reverse locking
1006	// order
1007	BReference<ValueNodeChild> nodeChildReference(nodeChild);
1008	BReference<ValueNode> oldNodeReference(oldNode);
1009	BReference<ValueNode> newNodeReference(newNode);
1010
1011	BMessage message(MSG_VALUE_NODE_CHANGED);
1012	if (message.AddPointer("nodeChild", nodeChild) == B_OK
1013		&& message.AddPointer("oldNode", oldNode) == B_OK
1014		&& message.AddPointer("newNode", newNode) == B_OK
1015		&& fIndirectTarget->Looper()->PostMessage(&message, fIndirectTarget)
1016			== B_OK) {
1017		nodeChildReference.Detach();
1018		oldNodeReference.Detach();
1019		newNodeReference.Detach();
1020	}
1021}
1022
1023
1024void
1025VariablesView::ContainerListener::ValueNodeChildrenCreated(ValueNode* node)
1026{
1027	// If the looper is already locked, invoke the model's hook synchronously.
1028	if (fIndirectTarget->Looper()->IsLocked()) {
1029		fModel->ValueNodeChildrenCreated(node);
1030		return;
1031	}
1032
1033	// looper not locked yet -- call asynchronously to avoid reverse locking
1034	// order
1035	BReference<ValueNode> nodeReference(node);
1036
1037	BMessage message(MSG_VALUE_NODE_CHILDREN_CREATED);
1038	if (message.AddPointer("node", node) == B_OK
1039		&& fIndirectTarget->Looper()->PostMessage(&message, fIndirectTarget)
1040			== B_OK) {
1041		nodeReference.Detach();
1042	}
1043}
1044
1045
1046void
1047VariablesView::ContainerListener::ValueNodeChildrenDeleted(ValueNode* node)
1048{
1049	// If the looper is already locked, invoke the model's hook synchronously.
1050	if (fIndirectTarget->Looper()->IsLocked()) {
1051		fModel->ValueNodeChildrenDeleted(node);
1052		return;
1053	}
1054
1055	// looper not locked yet -- call asynchronously to avoid reverse locking
1056	// order
1057	BReference<ValueNode> nodeReference(node);
1058
1059	BMessage message(MSG_VALUE_NODE_CHILDREN_DELETED);
1060	if (message.AddPointer("node", node) == B_OK
1061		&& fIndirectTarget->Looper()->PostMessage(&message, fIndirectTarget)
1062			== B_OK) {
1063		nodeReference.Detach();
1064	}
1065}
1066
1067
1068void
1069VariablesView::ContainerListener::ValueNodeValueChanged(ValueNode* node)
1070{
1071	// If the looper is already locked, invoke the model's hook synchronously.
1072	if (fIndirectTarget->Looper()->IsLocked()) {
1073		fModel->ValueNodeValueChanged(node);
1074		return;
1075	}
1076
1077	// looper not locked yet -- call asynchronously to avoid reverse locking
1078	// order
1079	BReference<ValueNode> nodeReference(node);
1080
1081	BMessage message(MSG_VALUE_NODE_VALUE_CHANGED);
1082	if (message.AddPointer("node", node) == B_OK
1083		&& fIndirectTarget->Looper()->PostMessage(&message, fIndirectTarget)
1084			== B_OK) {
1085		nodeReference.Detach();
1086	}
1087}
1088
1089
1090void
1091VariablesView::ContainerListener::ModelNodeHidden(ModelNode* node)
1092{
1093	BReference<ModelNode> nodeReference(node);
1094
1095	BMessage message(MSG_MODEL_NODE_HIDDEN);
1096	if (message.AddPointer("node", node) == B_OK
1097		&& fIndirectTarget->Looper()->PostMessage(&message, fIndirectTarget)
1098			== B_OK) {
1099		nodeReference.Detach();
1100	}
1101}
1102
1103
1104void
1105VariablesView::ContainerListener::ModelNodeValueRequested(ModelNode* node)
1106{
1107	BReference<ModelNode> nodeReference(node);
1108
1109	BMessage message(MSG_VALUE_NODE_NEEDS_VALUE);
1110	if (message.AddPointer("node", node) == B_OK
1111		&& fIndirectTarget->Looper()->PostMessage(&message, fIndirectTarget)
1112			== B_OK) {
1113		nodeReference.Detach();
1114	}
1115}
1116
1117
1118void
1119VariablesView::ContainerListener::ModelNodeRestoreViewStateRequested(
1120	ModelNode* node)
1121{
1122	BReference<ModelNode> nodeReference(node);
1123
1124	BMessage message(MSG_RESTORE_PARTIAL_VIEW_STATE);
1125	if (message.AddPointer("node", node) == B_OK
1126		&& fIndirectTarget->Looper()->PostMessage(&message, fIndirectTarget)
1127			== B_OK) {
1128		nodeReference.Detach();
1129	}
1130}
1131
1132
1133// #pragma mark - VariableTableModel
1134
1135
1136VariablesView::VariableTableModel::VariableTableModel(
1137	ValueNodeManager* manager)
1138	:
1139	fThread(NULL),
1140	fNodeManager(manager),
1141	fContainerListener(NULL),
1142	fNodeTable()
1143{
1144	fNodeManager->AcquireReference();
1145}
1146
1147
1148VariablesView::VariableTableModel::~VariableTableModel()
1149{
1150	fNodeManager->ReleaseReference();
1151}
1152
1153
1154status_t
1155VariablesView::VariableTableModel::Init()
1156{
1157	return fNodeTable.Init();
1158}
1159
1160
1161void
1162VariablesView::VariableTableModel::SetContainerListener(
1163	ContainerListener* listener)
1164{
1165	if (listener == fContainerListener)
1166		return;
1167
1168	if (fContainerListener != NULL) {
1169		if (fNodeManager != NULL)
1170			fNodeManager->RemoveListener(fContainerListener);
1171
1172		fContainerListener->SetModel(NULL);
1173	}
1174
1175	fContainerListener = listener;
1176
1177	if (fContainerListener != NULL) {
1178		fContainerListener->SetModel(this);
1179
1180		if (fNodeManager != NULL)
1181			fNodeManager->AddListener(fContainerListener);
1182	}
1183}
1184
1185
1186void
1187VariablesView::VariableTableModel::SetStackFrame(::Thread* thread,
1188	StackFrame* stackFrame)
1189{
1190	fThread = thread;
1191
1192	fNodeManager->SetStackFrame(thread, stackFrame);
1193
1194	int32 count = fNodes.CountItems();
1195	fNodeTable.Clear(true);
1196
1197	if (!fNodes.IsEmpty()) {
1198		for (int32 i = 0; i < count; i++)
1199			fNodes.ItemAt(i)->ReleaseReference();
1200		fNodes.MakeEmpty();
1201	}
1202
1203	NotifyNodesRemoved(TreeTablePath(), 0, count);
1204
1205	if (stackFrame == NULL)
1206		return;
1207
1208	ValueNodeContainer* container = fNodeManager->GetContainer();
1209	AutoLocker<ValueNodeContainer> containerLocker(container);
1210
1211	for (int32 i = 0; i < container->CountChildren(); i++) {
1212		VariableValueNodeChild* child = dynamic_cast<VariableValueNodeChild *>(
1213			container->ChildAt(i));
1214		_AddNode(child->GetVariable(), NULL, child);
1215		// top level nodes get their children added immediately
1216		// so those won't invoke our callback hook. Add them directly here.
1217		ValueNodeChildrenCreated(child->Node());
1218	}
1219}
1220
1221
1222void
1223VariablesView::VariableTableModel::ValueNodeChanged(ValueNodeChild* nodeChild,
1224	ValueNode* oldNode, ValueNode* newNode)
1225{
1226	AutoLocker<ValueNodeContainer> containerLocker(
1227		fNodeManager->GetContainer());
1228	ModelNode* modelNode = fNodeTable.Lookup(nodeChild);
1229	if (modelNode == NULL)
1230		return;
1231
1232	if (oldNode != NULL) {
1233		ValueNodeChildrenDeleted(oldNode);
1234		NotifyNodeChanged(modelNode);
1235	}
1236}
1237
1238
1239void
1240VariablesView::VariableTableModel::ValueNodeChildrenCreated(
1241	ValueNode* valueNode)
1242{
1243	AutoLocker<ValueNodeContainer> containerLocker(
1244		fNodeManager->GetContainer());
1245
1246	// check whether we know the node
1247	ValueNodeChild* nodeChild = valueNode->NodeChild();
1248	if (nodeChild == NULL)
1249		return;
1250
1251	ModelNode* modelNode = fNodeTable.Lookup(nodeChild);
1252	if (modelNode == NULL)
1253		return;
1254
1255	// Iterate through the children and create model nodes for the ones we
1256	// don't know yet.
1257	int32 childCount = valueNode->CountChildren();
1258	for (int32 i = 0; i < childCount; i++) {
1259		ValueNodeChild* child = valueNode->ChildAt(i);
1260		if (fNodeTable.Lookup(child) == NULL) {
1261			_AddNode(modelNode->GetVariable(), modelNode, child,
1262				child->IsInternal(), childCount == 1);
1263		}
1264
1265		ModelNode* childNode = fNodeTable.Lookup(child);
1266		if (childNode != NULL)
1267			fContainerListener->ModelNodeValueRequested(childNode);
1268	}
1269
1270	if (valueNode->ChildCreationNeedsValue())
1271		fContainerListener->ModelNodeRestoreViewStateRequested(modelNode);
1272}
1273
1274
1275void
1276VariablesView::VariableTableModel::ValueNodeChildrenDeleted(ValueNode* node)
1277{
1278	AutoLocker<ValueNodeContainer> containerLocker(
1279		fNodeManager->GetContainer());
1280
1281	// check whether we know the node
1282	ValueNodeChild* nodeChild = node->NodeChild();
1283	if (nodeChild == NULL)
1284		return;
1285
1286	ModelNode* modelNode = fNodeTable.Lookup(nodeChild);
1287	if (modelNode == NULL)
1288		return;
1289
1290	// in the case of an address node with a hidden child,
1291	// we want to send removal notifications for the children
1292	// instead.
1293	BReference<ModelNode> hiddenChild;
1294	if (modelNode->CountChildren() == 1
1295		&& modelNode->ChildAt(0)->IsHidden()) {
1296		hiddenChild.SetTo(modelNode->ChildAt(0));
1297		modelNode->RemoveChild(hiddenChild);
1298		modelNode = hiddenChild;
1299		fNodeTable.Remove(hiddenChild);
1300	}
1301
1302	for (int32 i = modelNode->CountChildren() - 1; i >= 0 ; i--) {
1303		BReference<ModelNode> childNode = modelNode->ChildAt(i);
1304		// recursively remove the current node's child hierarchy.
1305		if (childNode->CountChildren() != 0)
1306			ValueNodeChildrenDeleted(childNode->NodeChild()->Node());
1307
1308		TreeTablePath treePath;
1309		if (GetTreePath(childNode, treePath)) {
1310			int32 index = treePath.RemoveLastComponent();
1311			NotifyNodesRemoved(treePath, index, 1);
1312		}
1313		modelNode->RemoveChild(childNode);
1314		fNodeTable.Remove(childNode);
1315	}
1316}
1317
1318
1319void
1320VariablesView::VariableTableModel::ValueNodeValueChanged(ValueNode* valueNode)
1321{
1322	AutoLocker<ValueNodeContainer> containerLocker(
1323		fNodeManager->GetContainer());
1324
1325	// check whether we know the node
1326	ValueNodeChild* nodeChild = valueNode->NodeChild();
1327	if (nodeChild == NULL)
1328		return;
1329
1330	ModelNode* modelNode = fNodeTable.Lookup(nodeChild);
1331	if (modelNode == NULL)
1332		return;
1333
1334	// check whether the value actually changed
1335	Value* value = valueNode->GetValue();
1336	if (value == modelNode->GetValue())
1337		return;
1338
1339	// get a value handler
1340	ValueHandler* valueHandler;
1341	status_t error = ValueHandlerRoster::Default()->FindValueHandler(value,
1342		valueHandler);
1343	if (error != B_OK)
1344		return;
1345	BReference<ValueHandler> handlerReference(valueHandler, true);
1346
1347	// create a table cell renderer for the value
1348	TableCellValueRenderer* renderer = NULL;
1349	error = valueHandler->GetTableCellValueRenderer(value, renderer);
1350	if (error != B_OK)
1351		return;
1352
1353	BReference<TableCellValueRenderer> rendererReference(renderer, true);
1354	// set value/handler/renderer
1355	modelNode->SetValue(value);
1356	modelNode->SetValueHandler(valueHandler);
1357	modelNode->SetTableCellRenderer(renderer);
1358
1359	// we have to restore renderer settings here since until this point
1360	// we don't yet know what renderer is in use.
1361	if (renderer != NULL) {
1362		Settings* settings = renderer->GetSettings();
1363		if (settings != NULL)
1364			settings->RestoreValues(modelNode->GetLastRendererSettings());
1365	}
1366
1367	// notify table model listeners
1368	NotifyNodeChanged(modelNode);
1369}
1370
1371
1372int32
1373VariablesView::VariableTableModel::CountColumns() const
1374{
1375	return 3;
1376}
1377
1378
1379void*
1380VariablesView::VariableTableModel::Root() const
1381{
1382	return (void*)this;
1383}
1384
1385
1386int32
1387VariablesView::VariableTableModel::CountChildren(void* parent) const
1388{
1389	if (parent == this)
1390		return fNodes.CountItems();
1391
1392	// If the node only has a hidden child, pretend the node directly has the
1393	// child's children.
1394	ModelNode* modelNode = (ModelNode*)parent;
1395	int32 childCount = modelNode->CountChildren();
1396	if (childCount == 1) {
1397		ModelNode* child = modelNode->ChildAt(0);
1398		if (child->IsHidden())
1399			return child->CountChildren();
1400	}
1401
1402	return childCount;
1403}
1404
1405
1406void*
1407VariablesView::VariableTableModel::ChildAt(void* parent, int32 index) const
1408{
1409	if (parent == this)
1410		return fNodes.ItemAt(index);
1411
1412	// If the node only has a hidden child, pretend the node directly has the
1413	// child's children.
1414	ModelNode* modelNode = (ModelNode*)parent;
1415	int32 childCount = modelNode->CountChildren();
1416	if (childCount == 1) {
1417		ModelNode* child = modelNode->ChildAt(0);
1418		if (child->IsHidden())
1419			return child->ChildAt(index);
1420	}
1421
1422	return modelNode->ChildAt(index);
1423}
1424
1425
1426bool
1427VariablesView::VariableTableModel::GetValueAt(void* object, int32 columnIndex,
1428	BVariant& _value)
1429{
1430	ModelNode* node = (ModelNode*)object;
1431
1432	switch (columnIndex) {
1433		case 0:
1434			_value.SetTo(node->Name(), B_VARIANT_DONT_COPY_DATA);
1435			return true;
1436		case 1:
1437			if (node->GetValue() == NULL) {
1438				ValueLocation* location = node->NodeChild()->Location();
1439				if (location == NULL)
1440					return false;
1441
1442				ValueNode* childNode = node->NodeChild()->Node();
1443				if (childNode == NULL)
1444					return false;
1445
1446				Type* nodeChildRawType = childNode->GetType()->ResolveRawType(
1447					false);
1448				if (nodeChildRawType->Kind() == TYPE_COMPOUND)
1449				{
1450					if (location->CountPieces() > 1)
1451						return false;
1452
1453					BString data;
1454					ValuePieceLocation piece = location->PieceAt(0);
1455					if (piece.type != VALUE_PIECE_LOCATION_MEMORY)
1456						return false;
1457
1458					data.SetToFormat("[@ %#" B_PRIx64 "]", piece.address);
1459					_value.SetTo(data);
1460					return true;
1461				}
1462				return false;
1463			}
1464
1465			_value.SetTo(node, VALUE_NODE_TYPE);
1466			return true;
1467		case 2:
1468		{
1469			// use the type of the underlying value node, as it may
1470			// be different from the initially assigned top level type
1471			// due to casting
1472			ValueNode* childNode = node->NodeChild()->Node();
1473			if (childNode == NULL)
1474				return false;
1475
1476			Type* type = childNode->GetType();
1477			if (type == NULL)
1478				return false;
1479
1480			_value.SetTo(type->Name(), B_VARIANT_DONT_COPY_DATA);
1481			return true;
1482		}
1483		default:
1484			return false;
1485	}
1486}
1487
1488
1489void
1490VariablesView::VariableTableModel::NodeExpanded(ModelNode* node)
1491{
1492	AutoLocker<ValueNodeContainer> containerLocker(
1493		fNodeManager->GetContainer());
1494	// add children of all children
1495
1496	// If the node only has a hidden child, add the child's children instead.
1497	if (node->CountChildren() == 1) {
1498		ModelNode* child = node->ChildAt(0);
1499		if (child->IsHidden())
1500			node = child;
1501	}
1502
1503	// add the children
1504	for (int32 i = 0; ModelNode* child = node->ChildAt(i); i++)
1505		fNodeManager->AddChildNodes(child->NodeChild());
1506}
1507
1508
1509void
1510VariablesView::VariableTableModel::NotifyNodeChanged(ModelNode* node)
1511{
1512	if (!node->IsHidden()) {
1513		TreeTablePath treePath;
1514		if (GetTreePath(node, treePath)) {
1515			int32 index = treePath.RemoveLastComponent();
1516			NotifyNodesChanged(treePath, index, 1);
1517		}
1518	}
1519}
1520
1521
1522void
1523VariablesView::VariableTableModel::NotifyNodeHidden(ModelNode* node)
1524{
1525	fContainerListener->ModelNodeHidden(node);
1526}
1527
1528
1529bool
1530VariablesView::VariableTableModel::GetToolTipForTablePath(
1531	const TreeTablePath& path, int32 columnIndex, BToolTip** _tip)
1532{
1533	ModelNode* node = (ModelNode*)NodeForPath(path);
1534	if (node == NULL)
1535		return false;
1536
1537	BString tipData;
1538	ValueNodeChild* child = node->NodeChild();
1539	status_t error = child->LocationResolutionState();
1540	if (error != B_OK)
1541		tipData.SetToFormat("Unable to resolve location: %s", strerror(error));
1542	else {
1543		ValueNode* valueNode = child->Node();
1544		if (valueNode == NULL)
1545			return false;
1546		error = valueNode->LocationAndValueResolutionState();
1547		if (error != B_OK) {
1548			tipData.SetToFormat("Unable to resolve value: %s\n\n",
1549				strerror(error));
1550		}
1551
1552		switch (columnIndex) {
1553			case 0:
1554			{
1555				ValueLocation* location = child->Location();
1556				for (int32 i = 0; i < location->CountPieces(); i++) {
1557					ValuePieceLocation piece = location->PieceAt(i);
1558					BString pieceData;
1559					switch (piece.type) {
1560						case VALUE_PIECE_LOCATION_MEMORY:
1561							pieceData.SetToFormat("(%" B_PRId32 "): Address: "
1562								"%#" B_PRIx64 ", Size: %" B_PRId64 " bytes\n",
1563								i, piece.address, piece.size);
1564							break;
1565						case VALUE_PIECE_LOCATION_REGISTER:
1566						{
1567							Architecture* architecture = fThread->GetTeam()
1568								->GetArchitecture();
1569							pieceData.SetToFormat("(%" B_PRId32 "): Register "
1570								"(%s)\n", i,
1571								architecture->Registers()[piece.reg].Name());
1572							break;
1573						}
1574						default:
1575							break;
1576					}
1577
1578					tipData	+= pieceData;
1579				}
1580				tipData += "Editable: ";
1581				tipData += error == B_OK && location->IsWritable()
1582					? "Yes" : "No";
1583				break;
1584			}
1585			case 1:
1586			{
1587				Value* value = node->GetValue();
1588				if (value != NULL)
1589					value->ToString(tipData);
1590
1591				break;
1592			}
1593			default:
1594				break;
1595		}
1596	}
1597
1598	if (tipData.IsEmpty())
1599		return false;
1600
1601	*_tip = new(std::nothrow) BTextToolTip(tipData);
1602	if (*_tip == NULL)
1603		return false;
1604
1605	return true;
1606}
1607
1608
1609status_t
1610VariablesView::VariableTableModel::AddSyntheticNode(Variable* variable,
1611	ValueNodeChild*& _child, const char* presentationName)
1612{
1613	ValueNodeContainer* container = fNodeManager->GetContainer();
1614	AutoLocker<ValueNodeContainer> containerLocker(container);
1615
1616	status_t error;
1617	if (_child == NULL) {
1618		_child = new(std::nothrow) VariableValueNodeChild(variable);
1619		if (_child == NULL)
1620			return B_NO_MEMORY;
1621
1622		BReference<ValueNodeChild> childReference(_child, true);
1623		ValueNode* valueNode;
1624		if (_child->IsInternal())
1625			error = _child->CreateInternalNode(valueNode);
1626		else {
1627			error = TypeHandlerRoster::Default()->CreateValueNode(_child,
1628				_child->GetType(), NULL, valueNode);
1629		}
1630
1631		if (error != B_OK)
1632			return error;
1633
1634		_child->SetNode(valueNode);
1635		valueNode->ReleaseReference();
1636	}
1637
1638	container->AddChild(_child);
1639
1640	error = _AddNode(variable, NULL, _child);
1641	if (error != B_OK) {
1642		container->RemoveChild(_child);
1643		return error;
1644	}
1645
1646	// since we're injecting these nodes synthetically,
1647	// we have to manually ask the node manager to create any
1648	// applicable children; this would normally be done implicitly
1649	// for top level nodes, as they're added from the parameters/locals,
1650	// but not here.
1651	fNodeManager->AddChildNodes(_child);
1652
1653	ModelNode* childNode = fNodeTable.Lookup(_child);
1654	if (childNode != NULL) {
1655		if (presentationName != NULL)
1656			childNode->SetPresentationName(presentationName);
1657
1658		ValueNode* valueNode = _child->Node();
1659		if (valueNode->LocationAndValueResolutionState()
1660			== VALUE_NODE_UNRESOLVED) {
1661			fContainerListener->ModelNodeValueRequested(childNode);
1662		} else
1663			ValueNodeValueChanged(valueNode);
1664	}
1665	ValueNodeChildrenCreated(_child->Node());
1666
1667	return B_OK;
1668}
1669
1670
1671void
1672VariablesView::VariableTableModel::RemoveSyntheticNode(ModelNode* node)
1673{
1674	int32 index = fNodes.IndexOf(node);
1675	if (index < 0)
1676		return;
1677
1678	fNodeTable.Remove(node);
1679
1680	fNodes.RemoveItemAt(index);
1681
1682	NotifyNodesRemoved(TreeTablePath(), index, 1);
1683
1684	node->ReleaseReference();
1685}
1686
1687
1688status_t
1689VariablesView::VariableTableModel::_AddNode(Variable* variable,
1690	ModelNode* parent, ValueNodeChild* nodeChild, bool isPresentationNode,
1691	bool isOnlyChild)
1692{
1693	// Don't create nodes for unspecified types -- we can't get/show their
1694	// value anyway.
1695	Type* nodeChildRawType = nodeChild->GetType()->ResolveRawType(false);
1696	if (nodeChildRawType->Kind() == TYPE_UNSPECIFIED)
1697		return B_OK;
1698
1699	ModelNode* node = new(std::nothrow) ModelNode(parent, variable, nodeChild,
1700		isPresentationNode);
1701	BReference<ModelNode> nodeReference(node, true);
1702	if (node == NULL || node->Init() != B_OK)
1703		return B_NO_MEMORY;
1704
1705	int32 childIndex;
1706
1707	if (parent != NULL) {
1708		childIndex = parent->CountChildren();
1709
1710		if (!parent->AddChild(node))
1711			return B_NO_MEMORY;
1712		// the parent has a reference, now
1713	} else {
1714		childIndex = fNodes.CountItems();
1715
1716		if (!fNodes.AddItem(node))
1717			return B_NO_MEMORY;
1718		nodeReference.Detach();
1719			// the fNodes list has a reference, now
1720	}
1721
1722	fNodeTable.Insert(node);
1723
1724	// if an address type node has only a single child, and that child
1725	// is a compound type, mark it hidden
1726	if (isOnlyChild && parent != NULL) {
1727		ValueNode* parentValueNode = parent->NodeChild()->Node();
1728		if (parentValueNode != NULL) {
1729			if (parentValueNode->GetType()->ResolveRawType(false)->Kind()
1730				== TYPE_ADDRESS) {
1731				type_kind childKind = nodeChildRawType->Kind();
1732				if (childKind == TYPE_COMPOUND || childKind == TYPE_ARRAY) {
1733					node->SetHidden(true);
1734
1735					// we need to tell the listener about nodes like this so
1736					// any necessary actions can be taken for them (i.e. value
1737					// resolution), since they're otherwise invisible to
1738					// outsiders.
1739					NotifyNodeHidden(node);
1740				}
1741			}
1742		}
1743	}
1744
1745	// notify table model listeners
1746	if (!node->IsHidden()) {
1747		TreeTablePath path;
1748		if (parent == NULL || GetTreePath(parent, path))
1749			NotifyNodesAdded(path, childIndex, 1);
1750	}
1751
1752	// if the node is hidden, add its children
1753	if (node->IsHidden())
1754		fNodeManager->AddChildNodes(nodeChild);
1755
1756	return B_OK;
1757}
1758
1759
1760bool
1761VariablesView::VariableTableModel::GetTreePath(ModelNode* node,
1762	TreeTablePath& _path) const
1763{
1764	// recurse, if the node has a parent
1765	if (ModelNode* parent = node->Parent()) {
1766		if (!GetTreePath(parent, _path))
1767			return false;
1768
1769		if (node->IsHidden())
1770			return true;
1771
1772		return _path.AddComponent(parent->IndexOf(node));
1773	}
1774
1775	// no parent -- get the index and start the path
1776	int32 index = fNodes.IndexOf(node);
1777	_path.Clear();
1778	return index >= 0 && _path.AddComponent(index);
1779}
1780
1781
1782// #pragma mark - VariablesView
1783
1784
1785VariablesView::VariablesView(Listener* listener)
1786	:
1787	BGroupView(B_VERTICAL),
1788	fThread(NULL),
1789	fStackFrame(NULL),
1790	fVariableTable(NULL),
1791	fVariableTableModel(NULL),
1792	fContainerListener(NULL),
1793	fPreviousViewState(NULL),
1794	fViewStateHistory(NULL),
1795	fExpressions(NULL),
1796	fExpressionChildren(10, false),
1797	fTableCellContextMenuTracker(NULL),
1798	fPendingTypecastInfo(NULL),
1799	fTemporaryExpression(NULL),
1800	fFrameClearPending(false),
1801	fEditWindow(NULL),
1802	fListener(listener)
1803{
1804	SetName("Variables");
1805}
1806
1807
1808VariablesView::~VariablesView()
1809{
1810	if (fEditWindow != NULL)
1811		BMessenger(fEditWindow).SendMessage(B_QUIT_REQUESTED);
1812
1813	SetStackFrame(NULL, NULL);
1814	fVariableTable->SetTreeTableModel(NULL);
1815
1816	if (fPreviousViewState != NULL)
1817		fPreviousViewState->ReleaseReference();
1818	delete fViewStateHistory;
1819
1820	if (fVariableTableModel != NULL) {
1821		fVariableTableModel->SetContainerListener(NULL);
1822		delete fVariableTableModel;
1823	}
1824
1825	delete fContainerListener;
1826	if (fPendingTypecastInfo != NULL)
1827		fPendingTypecastInfo->ReleaseReference();
1828
1829	if (fTemporaryExpression != NULL)
1830		fTemporaryExpression->ReleaseReference();
1831
1832	if (fExpressions != NULL) {
1833		ExpressionInfoEntry* entry = fExpressions->Clear();
1834		while (entry != NULL) {
1835			ExpressionInfoEntry* next = entry->next;
1836			delete entry;
1837			entry = next;
1838		}
1839	}
1840
1841	delete fExpressions;
1842}
1843
1844
1845/*static*/ VariablesView*
1846VariablesView::Create(Listener* listener, ValueNodeManager* manager)
1847{
1848	VariablesView* self = new VariablesView(listener);
1849
1850	try {
1851		self->_Init(manager);
1852	} catch (...) {
1853		delete self;
1854		throw;
1855	}
1856
1857	return self;
1858}
1859
1860
1861void
1862VariablesView::SetStackFrame(::Thread* thread, StackFrame* stackFrame)
1863{
1864	bool updateValues = fFrameClearPending;
1865		// We only want to save previous values if we've continued
1866		// execution (i.e. thread/frame are being cleared).
1867		// Otherwise, we'll overwrite our previous values simply
1868		// by switching frames within the same stack trace, which isn't
1869		// desired behavior.
1870
1871	fFrameClearPending = false;
1872
1873	if (thread == fThread && stackFrame == fStackFrame)
1874		return;
1875
1876	_SaveViewState(updateValues);
1877
1878	_FinishContextMenu(true);
1879
1880	for (int32 i = 0; i < fExpressionChildren.CountItems(); i++)
1881		fExpressionChildren.ItemAt(i)->ReleaseReference();
1882	fExpressionChildren.MakeEmpty();
1883
1884	if (fThread != NULL)
1885		fThread->ReleaseReference();
1886	if (fStackFrame != NULL)
1887		fStackFrame->ReleaseReference();
1888
1889	fThread = thread;
1890	fStackFrame = stackFrame;
1891
1892	if (fThread != NULL)
1893		fThread->AcquireReference();
1894	if (fStackFrame != NULL)
1895		fStackFrame->AcquireReference();
1896
1897	fVariableTableModel->SetStackFrame(fThread, fStackFrame);
1898
1899	// request loading the parameter and variable values
1900	if (fThread != NULL && fStackFrame != NULL) {
1901		AutoLocker<Team> locker(fThread->GetTeam());
1902
1903		void* root = fVariableTableModel->Root();
1904		int32 count = fVariableTableModel->CountChildren(root);
1905		for (int32 i = 0; i < count; i++) {
1906			ModelNode* node = (ModelNode*)fVariableTableModel->ChildAt(root, i);
1907			_RequestNodeValue(node);
1908		}
1909
1910		_RestoreExpressionNodes();
1911	}
1912
1913	_RestoreViewState();
1914}
1915
1916
1917void
1918VariablesView::MessageReceived(BMessage* message)
1919{
1920	switch (message->what) {
1921		case MSG_SHOW_INSPECTOR_WINDOW:
1922		{
1923			// TODO: it'd probably be more ideal to extend the context
1924			// action mechanism to allow one to specify an explicit
1925			// target for each action rather than them all defaulting
1926			// to targetting here.
1927			Looper()->PostMessage(message);
1928			break;
1929		}
1930		case MSG_SHOW_VARIABLE_EDIT_WINDOW:
1931		{
1932			if (fEditWindow != NULL)
1933				fEditWindow->Activate();
1934			else {
1935				ModelNode* node = NULL;
1936				if (message->FindPointer("node", reinterpret_cast<void**>(
1937						&node)) != B_OK) {
1938					break;
1939				}
1940
1941				Value* value = NULL;
1942				if (message->FindPointer("value", reinterpret_cast<void**>(
1943						&value)) != B_OK) {
1944					break;
1945				}
1946
1947				_HandleEditVariableRequest(node, value);
1948			}
1949			break;
1950		}
1951		case MSG_VARIABLE_EDIT_WINDOW_CLOSED:
1952		{
1953			fEditWindow = NULL;
1954			break;
1955		}
1956		case MSG_WRITE_VARIABLE_VALUE:
1957		{
1958			Value* value = NULL;
1959			if (message->FindPointer("value", reinterpret_cast<void**>(
1960					&value)) != B_OK) {
1961				break;
1962			}
1963
1964			BReference<Value> valueReference(value, true);
1965
1966			ValueNode* node = NULL;
1967			if (message->FindPointer("node", reinterpret_cast<void**>(
1968					&node)) != B_OK) {
1969				break;
1970			}
1971
1972			fListener->ValueNodeWriteRequested(node,
1973				fStackFrame->GetCpuState(), value);
1974			break;
1975		}
1976		case MSG_SHOW_TYPECAST_NODE_PROMPT:
1977		{
1978			BMessage* promptMessage = new(std::nothrow) BMessage(
1979				MSG_TYPECAST_NODE);
1980
1981			if (promptMessage == NULL)
1982				return;
1983
1984			ObjectDeleter<BMessage> messageDeleter(promptMessage);
1985			promptMessage->AddPointer("node", fVariableTable
1986				->SelectionModel()->NodeAt(0));
1987			PromptWindow* promptWindow = new(std::nothrow) PromptWindow(
1988				"Specify Type", "Type: ", NULL, BMessenger(this),
1989				promptMessage);
1990			if (promptWindow == NULL)
1991				return;
1992
1993			messageDeleter.Detach();
1994			promptWindow->CenterOnScreen();
1995			promptWindow->Show();
1996			break;
1997		}
1998		case MSG_TYPECAST_NODE:
1999		{
2000			ModelNode* node = NULL;
2001			if (message->FindPointer("node", reinterpret_cast<void **>(&node))
2002					!= B_OK) {
2003				break;
2004			}
2005
2006			BString typeExpression;
2007			if (message->FindString("text", &typeExpression) == B_OK) {
2008				if (typeExpression.IsEmpty())
2009					break;
2010
2011				if (fPendingTypecastInfo != NULL)
2012					fPendingTypecastInfo->ReleaseReference();
2013
2014				fPendingTypecastInfo = new(std::nothrow)
2015					VariablesExpressionInfo(typeExpression, node);
2016				if (fPendingTypecastInfo == NULL) {
2017					// TODO: notify user
2018					break;
2019				}
2020
2021				fPendingTypecastInfo->AddListener(this);
2022				fListener->ExpressionEvaluationRequested(fPendingTypecastInfo,
2023					fStackFrame, fThread);
2024			}
2025			break;
2026		}
2027		case MSG_TYPECAST_TO_ARRAY:
2028		{
2029			ModelNode* node = NULL;
2030			if (message->FindPointer("node", reinterpret_cast<void **>(&node))
2031				!= B_OK) {
2032				break;
2033			}
2034
2035			Type* baseType = dynamic_cast<AddressType*>(node->NodeChild()
2036					->Node()->GetType())->BaseType();
2037			ArrayType* arrayType = NULL;
2038			if (baseType->CreateDerivedArrayType(0, kMaxArrayElementCount,
2039				false, arrayType) != B_OK) {
2040				break;
2041			}
2042
2043			AddressType* addressType = NULL;
2044			BReference<Type> typeRef(arrayType, true);
2045			if (arrayType->CreateDerivedAddressType(DERIVED_TYPE_POINTER,
2046					addressType) != B_OK) {
2047				break;
2048			}
2049
2050			typeRef.Detach();
2051			typeRef.SetTo(addressType, true);
2052			ValueNode* valueNode = NULL;
2053			if (TypeHandlerRoster::Default()->CreateValueNode(
2054					node->NodeChild(), addressType, NULL, valueNode) != B_OK) {
2055				break;
2056			}
2057
2058			typeRef.Detach();
2059			node->NodeChild()->SetNode(valueNode);
2060			node->SetCastedType(addressType);
2061			fVariableTableModel->NotifyNodeChanged(node);
2062			break;
2063		}
2064		case MSG_SHOW_CONTAINER_RANGE_PROMPT:
2065		{
2066			ModelNode* node = (ModelNode*)fVariableTable
2067				->SelectionModel()->NodeAt(0);
2068			int32 lowerBound, upperBound;
2069			ValueNode* valueNode = node->NodeChild()->Node();
2070			if (!valueNode->IsRangedContainer()) {
2071				valueNode = node->ChildAt(0)->NodeChild()->Node();
2072				if (!valueNode->IsRangedContainer())
2073					break;
2074			}
2075
2076			bool fixedRange = valueNode->IsContainerRangeFixed();
2077			if (valueNode->SupportedChildRange(lowerBound, upperBound)
2078				!= B_OK) {
2079				break;
2080			}
2081
2082			BMessage* promptMessage = new(std::nothrow) BMessage(
2083				MSG_SET_CONTAINER_RANGE);
2084			if (promptMessage == NULL)
2085				break;
2086
2087			ObjectDeleter<BMessage> messageDeleter(promptMessage);
2088			promptMessage->AddPointer("node", node);
2089			promptMessage->AddBool("fixedRange", fixedRange);
2090			BString infoText;
2091			if (fixedRange) {
2092				infoText.SetToFormat("Allowed range: %" B_PRId32
2093					"-%" B_PRId32 ".", lowerBound, upperBound);
2094			} else {
2095				infoText.SetToFormat("Current range: %" B_PRId32
2096					"-%" B_PRId32 ".", lowerBound, upperBound);
2097			}
2098
2099			PromptWindow* promptWindow = new(std::nothrow) PromptWindow(
2100				"Set Range", "Range: ", infoText.String(), BMessenger(this),
2101				promptMessage);
2102			if (promptWindow == NULL)
2103				return;
2104
2105			messageDeleter.Detach();
2106			promptWindow->CenterOnScreen();
2107			promptWindow->Show();
2108			break;
2109		}
2110		case MSG_SET_CONTAINER_RANGE:
2111		{
2112			ModelNode* node = (ModelNode*)fVariableTable
2113				->SelectionModel()->NodeAt(0);
2114			int32 lowerBound, upperBound;
2115			ValueNode* valueNode = node->NodeChild()->Node();
2116			if (!valueNode->IsRangedContainer())
2117				valueNode = node->ChildAt(0)->NodeChild()->Node();
2118			if (valueNode->SupportedChildRange(lowerBound, upperBound) != B_OK)
2119				break;
2120
2121			bool fixedRange = message->FindBool("fixedRange");
2122
2123			BString rangeExpression = message->FindString("text");
2124			if (rangeExpression.Length() == 0)
2125				break;
2126
2127			RangeList ranges;
2128			status_t result = UiUtils::ParseRangeExpression(
2129				rangeExpression, lowerBound, upperBound, fixedRange, ranges);
2130			if (result != B_OK)
2131				break;
2132
2133			valueNode->ClearChildren();
2134			for (int32 i = 0; i < ranges.CountRanges(); i++) {
2135				const Range* range = ranges.RangeAt(i);
2136				result = valueNode->CreateChildrenInRange(
2137					fThread->GetTeam()->GetTeamTypeInformation(),
2138					range->lowerBound, range->upperBound);
2139				if (result != B_OK)
2140					break;
2141			}
2142			break;
2143		}
2144		case MSG_SHOW_WATCH_VARIABLE_PROMPT:
2145		{
2146			ModelNode* node = reinterpret_cast<ModelNode*>(
2147				fVariableTable->SelectionModel()->NodeAt(0));
2148			ValueLocation* location = node->NodeChild()->Location();
2149			ValuePieceLocation piece = location->PieceAt(0);
2150			if (piece.type != VALUE_PIECE_LOCATION_MEMORY)
2151				break;
2152
2153			BMessage looperMessage(*message);
2154			looperMessage.AddUInt64("address", piece.address);
2155			looperMessage.AddInt32("length", piece.size);
2156			looperMessage.AddUInt32("type", B_DATA_READ_WRITE_WATCHPOINT);
2157			Looper()->PostMessage(&looperMessage);
2158			break;
2159		}
2160		case MSG_ADD_WATCH_EXPRESSION:
2161		{
2162			BMessage looperMessage(MSG_SHOW_EXPRESSION_PROMPT_WINDOW);
2163			looperMessage.AddPointer("target", this);
2164			Looper()->PostMessage(&looperMessage);
2165			break;
2166		}
2167		case MSG_REMOVE_WATCH_EXPRESSION:
2168		{
2169			ModelNode* node;
2170			if (message->FindPointer("node", reinterpret_cast<void**>(&node))
2171				!= B_OK) {
2172				break;
2173			}
2174
2175			_RemoveExpression(node);
2176			break;
2177		}
2178		case MSG_ADD_NEW_EXPRESSION:
2179		{
2180			const char* expression;
2181			if (message->FindString("expression", &expression) != B_OK)
2182				break;
2183
2184			bool persistentExpression = message->FindBool("persistent");
2185
2186			ExpressionInfo* info;
2187			status_t error = _AddExpression(expression, persistentExpression,
2188				info);
2189			if (error != B_OK) {
2190				// TODO: notify user of failure
2191				break;
2192			}
2193
2194			fListener->ExpressionEvaluationRequested(info, fStackFrame,
2195				fThread);
2196			break;
2197		}
2198		case MSG_EXPRESSION_EVALUATED:
2199		{
2200			ExpressionInfo* info;
2201			status_t result;
2202			ExpressionResult* value = NULL;
2203			if (message->FindPointer("info",
2204					reinterpret_cast<void**>(&info)) != B_OK
2205				|| message->FindInt32("result", &result) != B_OK) {
2206				break;
2207			}
2208
2209			BReference<ExpressionResult> valueReference;
2210			if (message->FindPointer("value", reinterpret_cast<void**>(&value))
2211				== B_OK) {
2212				valueReference.SetTo(value, true);
2213			}
2214
2215			VariablesExpressionInfo* variableInfo
2216				= dynamic_cast<VariablesExpressionInfo*>(info);
2217			if (variableInfo != NULL) {
2218				if (fPendingTypecastInfo == variableInfo) {
2219					_HandleTypecastResult(result, value);
2220					fPendingTypecastInfo->ReleaseReference();
2221					fPendingTypecastInfo = NULL;
2222				}
2223			} else {
2224				_AddExpressionNode(info, result, value);
2225				if (info == fTemporaryExpression) {
2226					info->ReleaseReference();
2227					fTemporaryExpression = NULL;
2228				}
2229			}
2230
2231			break;
2232		}
2233		case MSG_USE_AUTOMATIC_HANDLER:
2234		case MSG_USE_EXPLICIT_HANDLER:
2235		{
2236			TypeHandler* handler = NULL;
2237			ModelNode* node = NULL;
2238			if (message->FindPointer("node", reinterpret_cast<void **>(&node))
2239					!= B_OK) {
2240				break;
2241			}
2242
2243			if (message->what == MSG_USE_EXPLICIT_HANDLER
2244				&& message->FindPointer("handler", reinterpret_cast<void**>(
2245						&handler)) != B_OK) {
2246				break;
2247			}
2248
2249			ValueNode* newNode;
2250			ValueNodeChild* child = node->NodeChild();
2251			if (TypeHandlerRoster::Default()->CreateValueNode(child,
2252					child->GetType(), handler, newNode) != B_OK) {
2253				return;
2254			}
2255
2256			node->SetTypeHandler(handler);
2257			child->SetNode(newNode);
2258			_RequestNodeValue(node);
2259			break;
2260		}
2261		case MSG_VALUE_NODE_CHANGED:
2262		{
2263			ValueNodeChild* nodeChild;
2264			ValueNode* oldNode;
2265			ValueNode* newNode;
2266			if (message->FindPointer("nodeChild", (void**)&nodeChild) == B_OK
2267				&& message->FindPointer("oldNode", (void**)&oldNode) == B_OK
2268				&& message->FindPointer("newNode", (void**)&newNode) == B_OK) {
2269				BReference<ValueNodeChild> nodeChildReference(nodeChild, true);
2270				BReference<ValueNode> oldNodeReference(oldNode, true);
2271				BReference<ValueNode> newNodeReference(newNode, true);
2272
2273				fVariableTableModel->ValueNodeChanged(nodeChild, oldNode,
2274					newNode);
2275			}
2276
2277			break;
2278		}
2279		case MSG_VALUE_NODE_CHILDREN_CREATED:
2280		{
2281			ValueNode* node;
2282			if (message->FindPointer("node", (void**)&node) == B_OK) {
2283				BReference<ValueNode> newNodeReference(node, true);
2284				fVariableTableModel->ValueNodeChildrenCreated(node);
2285			}
2286
2287			break;
2288		}
2289		case MSG_VALUE_NODE_CHILDREN_DELETED:
2290		{
2291			ValueNode* node;
2292			if (message->FindPointer("node", (void**)&node) == B_OK) {
2293				BReference<ValueNode> newNodeReference(node, true);
2294				fVariableTableModel->ValueNodeChildrenDeleted(node);
2295			}
2296
2297			break;
2298		}
2299		case MSG_VALUE_NODE_VALUE_CHANGED:
2300		{
2301			ValueNode* node;
2302			if (message->FindPointer("node", (void**)&node) == B_OK) {
2303				BReference<ValueNode> newNodeReference(node, true);
2304				fVariableTableModel->ValueNodeValueChanged(node);
2305			}
2306
2307			break;
2308		}
2309		case MSG_RESTORE_PARTIAL_VIEW_STATE:
2310		{
2311			ModelNode* node;
2312			if (message->FindPointer("node", (void**)&node) == B_OK) {
2313				BReference<ModelNode> nodeReference(node, true);
2314				TreeTablePath path;
2315				if (fVariableTableModel->GetTreePath(node, path)) {
2316					FunctionID* functionID = fStackFrame->Function()
2317						->GetFunctionID();
2318					if (functionID == NULL)
2319						return;
2320					BReference<FunctionID> functionIDReference(functionID,
2321						true);
2322					VariablesViewState* viewState = fViewStateHistory
2323						->GetState(fThread->ID(), functionID);
2324					if (viewState != NULL) {
2325						_ApplyViewStateDescendentNodeInfos(viewState, node,
2326							path);
2327					}
2328				}
2329			}
2330			break;
2331		}
2332		case MSG_VALUE_NODE_NEEDS_VALUE:
2333		case MSG_MODEL_NODE_HIDDEN:
2334		{
2335			ModelNode* node;
2336			if (message->FindPointer("node", (void**)&node) == B_OK) {
2337				BReference<ModelNode> modelNodeReference(node, true);
2338				_RequestNodeValue(node);
2339			}
2340
2341			break;
2342		}
2343		case MSG_VARIABLES_VIEW_CONTEXT_MENU_DONE:
2344		{
2345			_FinishContextMenu(false);
2346			break;
2347		}
2348		case MSG_VARIABLES_VIEW_NODE_SETTINGS_CHANGED:
2349		{
2350			ModelNode* node;
2351			if (message->FindPointer("node", (void**)&node) != B_OK)
2352				break;
2353			BReference<ModelNode> nodeReference(node, true);
2354
2355			fVariableTableModel->NotifyNodeChanged(node);
2356			break;
2357		}
2358		case B_COPY:
2359		{
2360			_CopyVariableValueToClipboard();
2361			break;
2362		}
2363		default:
2364			BGroupView::MessageReceived(message);
2365			break;
2366	}
2367}
2368
2369
2370void
2371VariablesView::DetachedFromWindow()
2372{
2373	_FinishContextMenu(true);
2374}
2375
2376
2377void
2378VariablesView::LoadSettings(const BMessage& settings)
2379{
2380	BMessage tableSettings;
2381	if (settings.FindMessage("variableTable", &tableSettings) == B_OK) {
2382		GuiSettingsUtils::UnarchiveTableSettings(tableSettings,
2383			fVariableTable);
2384	}
2385}
2386
2387
2388status_t
2389VariablesView::SaveSettings(BMessage& settings)
2390{
2391	settings.MakeEmpty();
2392
2393	BMessage tableSettings;
2394	status_t result = GuiSettingsUtils::ArchiveTableSettings(tableSettings,
2395		fVariableTable);
2396	if (result == B_OK)
2397		result = settings.AddMessage("variableTable", &tableSettings);
2398
2399	return result;
2400}
2401
2402
2403void
2404VariablesView::SetStackFrameClearPending()
2405{
2406	fFrameClearPending = true;
2407}
2408
2409
2410void
2411VariablesView::TreeTableNodeExpandedChanged(TreeTable* table,
2412	const TreeTablePath& path, bool expanded)
2413{
2414	if (fFrameClearPending)
2415		return;
2416
2417	if (expanded) {
2418		ModelNode* node = (ModelNode*)fVariableTableModel->NodeForPath(path);
2419		if (node == NULL)
2420			return;
2421
2422		fVariableTableModel->NodeExpanded(node);
2423
2424		// request the values of all children that don't have any yet
2425
2426		// If the node only has a hidden child, directly load the child's
2427		// children's values.
2428		if (node->CountChildren() == 1) {
2429			ModelNode* child = node->ChildAt(0);
2430			if (child->IsHidden())
2431				node = child;
2432		}
2433
2434		// request the values
2435		for (int32 i = 0; ModelNode* child = node->ChildAt(i); i++) {
2436			if (child->IsPresentationNode())
2437				continue;
2438
2439			_RequestNodeValue(child);
2440		}
2441	}
2442}
2443
2444
2445void
2446VariablesView::TreeTableNodeInvoked(TreeTable* table,
2447	const TreeTablePath& path)
2448{
2449	ModelNode* node = (ModelNode*)fVariableTableModel->NodeForPath(path);
2450	if (node == NULL)
2451		return;
2452
2453	ValueNodeChild* child = node->NodeChild();
2454
2455	if (child->LocationResolutionState() != B_OK)
2456		return;
2457
2458	ValueLocation* location = child->Location();
2459	if (!location->IsWritable())
2460		return;
2461
2462	Value* value = node->GetValue();
2463	if (value == NULL)
2464		return;
2465
2466	BMessage message(MSG_SHOW_VARIABLE_EDIT_WINDOW);
2467	message.AddPointer("node", node);
2468	message.AddPointer("value", value);
2469
2470	BMessenger(this).SendMessage(&message);
2471}
2472
2473
2474void
2475VariablesView::TreeTableCellMouseDown(TreeTable* table,
2476	const TreeTablePath& path, int32 columnIndex, BPoint screenWhere,
2477	uint32 buttons)
2478{
2479	if ((buttons & B_SECONDARY_MOUSE_BUTTON) == 0)
2480		return;
2481
2482	if (fFrameClearPending)
2483		return;
2484
2485	_FinishContextMenu(true);
2486
2487	ModelNode* node = (ModelNode*)fVariableTableModel->NodeForPath(path);
2488	if (node == NULL)
2489		return;
2490
2491	Settings* settings = NULL;
2492	SettingsMenu* settingsMenu = NULL;
2493	BReference<SettingsMenu> settingsMenuReference;
2494	status_t error = B_OK;
2495	TableCellValueRenderer* cellRenderer = node->TableCellRenderer();
2496	if (cellRenderer != NULL) {
2497		settings = cellRenderer->GetSettings();
2498		if (settings != NULL) {
2499			error = node->GetValueHandler()
2500				->CreateTableCellValueSettingsMenu(node->GetValue(), settings,
2501					settingsMenu);
2502			settingsMenuReference.SetTo(settingsMenu, true);
2503			if (error != B_OK)
2504				return;
2505		}
2506	}
2507
2508	TableCellContextMenuTracker* tracker = new(std::nothrow)
2509		TableCellContextMenuTracker(node, Looper(), this);
2510	BReference<TableCellContextMenuTracker> trackerReference(tracker);
2511
2512	ContextActionList* preActionList;
2513	ContextActionList* postActionList;
2514
2515	error = _GetContextActionsForNode(node, preActionList, postActionList);
2516	if (error != B_OK)
2517		return;
2518
2519	BPrivate::ObjectDeleter<ContextActionList> preActionListDeleter(
2520		preActionList);
2521
2522	BPrivate::ObjectDeleter<ContextActionList> postActionListDeleter(
2523		postActionList);
2524
2525	if (tracker == NULL || tracker->Init(settings, settingsMenu, preActionList,
2526		postActionList) != B_OK) {
2527		return;
2528	}
2529
2530	fTableCellContextMenuTracker = trackerReference.Detach();
2531	fTableCellContextMenuTracker->ShowMenu(screenWhere);
2532}
2533
2534
2535void
2536VariablesView::ExpressionEvaluated(ExpressionInfo* info, status_t result,
2537	ExpressionResult* value)
2538{
2539	BMessage message(MSG_EXPRESSION_EVALUATED);
2540	message.AddPointer("info", info);
2541	message.AddInt32("result", result);
2542	BReference<ExpressionResult> valueReference;
2543
2544	if (value != NULL) {
2545		valueReference.SetTo(value);
2546		message.AddPointer("value", value);
2547	}
2548
2549	if (BMessenger(this).SendMessage(&message) == B_OK)
2550		valueReference.Detach();
2551}
2552
2553
2554void
2555VariablesView::_Init(ValueNodeManager* manager)
2556{
2557	fVariableTable = new TreeTable("variable list", 0, B_FANCY_BORDER);
2558	fVariableTable->SetFont(B_FONT_ROW, be_fixed_font);
2559	AddChild(fVariableTable->ToView());
2560	fVariableTable->SetSortingEnabled(false);
2561
2562	// columns
2563	const float padding = be_control_look->DefaultLabelSpacing();
2564	fVariableTable->AddColumn(new StringTableColumn(0, "Variable",
2565		be_fixed_font->StringWidth("VariableName") + padding, 40, 1000,
2566		B_TRUNCATE_END, B_ALIGN_LEFT));
2567	fVariableTable->AddColumn(new VariableValueColumn(1, "Value",
2568		be_fixed_font->StringWidth("0xffffffff00000000") + padding, 40, 1000,
2569		B_TRUNCATE_END, B_ALIGN_RIGHT));
2570	fVariableTable->AddColumn(new StringTableColumn(2, "Type",
2571		be_fixed_font->StringWidth("std::vector<int32_t>") + padding, 40, 1000,
2572		B_TRUNCATE_END, B_ALIGN_LEFT));
2573
2574	fVariableTableModel = new VariableTableModel(manager);
2575	if (fVariableTableModel->Init() != B_OK)
2576		throw std::bad_alloc();
2577	fVariableTable->SetTreeTableModel(fVariableTableModel);
2578	fVariableTable->SetToolTipProvider(fVariableTableModel);
2579
2580	fContainerListener = new ContainerListener(this);
2581	fVariableTableModel->SetContainerListener(fContainerListener);
2582
2583	fVariableTable->AddTreeTableListener(this);
2584
2585	fViewStateHistory = new VariablesViewStateHistory;
2586	if (fViewStateHistory->Init() != B_OK)
2587		throw std::bad_alloc();
2588
2589	fExpressions = new ExpressionInfoTable();
2590	if (fExpressions->Init() != B_OK)
2591		throw std::bad_alloc();
2592}
2593
2594
2595void
2596VariablesView::_RequestNodeValue(ModelNode* node)
2597{
2598	// get the node child and its container
2599	ValueNodeChild* nodeChild = node->NodeChild();
2600	ValueNodeContainer* container = nodeChild->Container();
2601
2602	BReference<ValueNodeContainer> containerReference(container);
2603	AutoLocker<ValueNodeContainer> containerLocker(container);
2604
2605	if (container == NULL || nodeChild->Container() != container)
2606		return;
2607
2608	// get the value node and check whether its value has not yet been resolved
2609	ValueNode* valueNode = nodeChild->Node();
2610	if (valueNode == NULL) {
2611		ModelNode* parent = node->Parent();
2612		if (parent != NULL) {
2613			TreeTablePath path;
2614			if (!fVariableTableModel->GetTreePath(parent, path))
2615				return;
2616
2617			// if the parent node was already expanded when the child was
2618			// added, we may not yet have added a value node.
2619			// Notify the table model that this needs to be done.
2620			if (fVariableTable->IsNodeExpanded(path))
2621				fVariableTableModel->NodeExpanded(parent);
2622		}
2623	}
2624
2625	if (valueNode == NULL || valueNode->LocationAndValueResolutionState()
2626		!= VALUE_NODE_UNRESOLVED) {
2627		return;
2628	}
2629
2630	BReference<ValueNode> valueNodeReference(valueNode);
2631	containerLocker.Unlock();
2632
2633	// request resolution of the value
2634	fListener->ValueNodeValueRequested(fStackFrame != NULL
2635			? fStackFrame->GetCpuState() : NULL, container, valueNode);
2636}
2637
2638
2639status_t
2640VariablesView::_GetContextActionsForNode(ModelNode* node,
2641	ContextActionList*& _preActions, ContextActionList*& _postActions)
2642{
2643	_preActions = NULL;
2644	_postActions = NULL;
2645
2646	ValueLocation* location = node->NodeChild()->Location();
2647
2648	_preActions = new(std::nothrow) ContextActionList;
2649	if (_preActions == NULL)
2650		return B_NO_MEMORY;
2651
2652	BPrivate::ObjectDeleter<ContextActionList> preActionListDeleter(
2653		_preActions);
2654
2655	status_t result = B_OK;
2656	BMessage* message = NULL;
2657
2658	// only show the Inspect option if the value is in fact located
2659	// in memory.
2660	if (location != NULL) {
2661		if (location->PieceAt(0).type  == VALUE_PIECE_LOCATION_MEMORY) {
2662			result = _AddContextAction("Inspect", MSG_SHOW_INSPECTOR_WINDOW,
2663				_preActions, message);
2664			if (result != B_OK)
2665				return result;
2666			message->AddUInt64("address", location->PieceAt(0).address);
2667		}
2668
2669		ValueNodeChild* child = node->NodeChild();
2670		ValueNode* valueNode = child->Node();
2671
2672		result = _AddTypeHandlerMenuIfNeeded(node, _preActions);
2673		if (result != B_OK)
2674			return result;
2675
2676		if (valueNode != NULL) {
2677			Value* value = valueNode->GetValue();
2678			if (location->IsWritable() && value != NULL) {
2679				result = _AddContextAction("Edit" B_UTF8_ELLIPSIS,
2680					MSG_SHOW_VARIABLE_EDIT_WINDOW, _preActions, message);
2681				if (result != B_OK)
2682					return result;
2683				message->AddPointer("node", node);
2684				message->AddPointer("value", value);
2685			}
2686			AddressType* type = dynamic_cast<AddressType*>(valueNode->GetType());
2687			if (type != NULL && type->BaseType() != NULL) {
2688				result = _AddContextAction("Cast to array", MSG_TYPECAST_TO_ARRAY,
2689					_preActions, message);
2690				if (result != B_OK)
2691					return result;
2692				message->AddPointer("node", node);
2693			}
2694		}
2695
2696		result = _AddContextAction("Cast as" B_UTF8_ELLIPSIS,
2697			MSG_SHOW_TYPECAST_NODE_PROMPT, _preActions, message);
2698		if (result != B_OK)
2699			return result;
2700
2701		result = _AddContextAction("Watch" B_UTF8_ELLIPSIS,
2702			MSG_SHOW_WATCH_VARIABLE_PROMPT, _preActions, message);
2703		if (result != B_OK)
2704			return result;
2705
2706		if (valueNode == NULL)
2707			return B_OK;
2708
2709		if (valueNode->LocationAndValueResolutionState() == B_OK) {
2710			result = _AddContextAction("Copy Value", B_COPY, _preActions, message);
2711			if (result != B_OK)
2712				return result;
2713		}
2714
2715		bool addRangedContainerItem = false;
2716		// if the current node isn't itself a ranged container, check if it
2717		// contains a hidden node which is, since in the latter case we
2718		// want to present the range selection as well.
2719		if (valueNode->IsRangedContainer())
2720			addRangedContainerItem = true;
2721		else if (node->CountChildren() == 1 && node->ChildAt(0)->IsHidden()) {
2722			valueNode = node->ChildAt(0)->NodeChild()->Node();
2723			if (valueNode != NULL && valueNode->IsRangedContainer())
2724				addRangedContainerItem = true;
2725		}
2726
2727		if (addRangedContainerItem) {
2728			result = _AddContextAction("Set visible range" B_UTF8_ELLIPSIS,
2729				MSG_SHOW_CONTAINER_RANGE_PROMPT, _preActions, message);
2730			if (result != B_OK)
2731				return result;
2732		}
2733	}
2734
2735	_postActions = new(std::nothrow) ContextActionList;
2736	if (_postActions == NULL)
2737		return B_NO_MEMORY;
2738
2739	BPrivate::ObjectDeleter<ContextActionList> postActionListDeleter(
2740		_postActions);
2741
2742	result = _AddContextAction("Add watch expression" B_UTF8_ELLIPSIS,
2743		MSG_ADD_WATCH_EXPRESSION, _postActions, message);
2744	if (result != B_OK)
2745		return result;
2746
2747	if (fExpressionChildren.HasItem(node->NodeChild())) {
2748		result = _AddContextAction("Remove watch expression",
2749			MSG_REMOVE_WATCH_EXPRESSION, _postActions, message);
2750		if (result != B_OK)
2751			return result;
2752		message->AddPointer("node", node);
2753	}
2754
2755	preActionListDeleter.Detach();
2756	postActionListDeleter.Detach();
2757
2758	return B_OK;
2759}
2760
2761
2762status_t
2763VariablesView::_AddContextAction(const char* action, uint32 what,
2764	ContextActionList* actions, BMessage*& _message)
2765{
2766	ActionMenuItem* item = NULL;
2767	status_t result = _CreateContextAction(action, what, item);
2768	if (result != B_OK)
2769		return result;
2770
2771	ObjectDeleter<ActionMenuItem> actionDeleter(item);
2772	if (!actions->AddItem(item))
2773		return B_NO_MEMORY;
2774
2775	actionDeleter.Detach();
2776	_message = item->Message();
2777
2778	return B_OK;
2779}
2780
2781
2782status_t
2783VariablesView::_CreateContextAction(const char* action, uint32 what,
2784	ActionMenuItem*& _item)
2785{
2786	BMessage* message = new(std::nothrow) BMessage(what);
2787	if (message == NULL)
2788		return B_NO_MEMORY;
2789
2790	ObjectDeleter<BMessage> messageDeleter(message);
2791
2792	_item = new(std::nothrow) ActionMenuItem(action,
2793		message);
2794	if (_item == NULL)
2795		return B_NO_MEMORY;
2796
2797	messageDeleter.Detach();
2798
2799	return B_OK;
2800}
2801
2802
2803status_t
2804VariablesView::_AddTypeHandlerMenuIfNeeded(ModelNode* node,
2805	ContextActionList* actions)
2806{
2807	ValueNodeChild* child = node->NodeChild();
2808
2809	if (node->CountChildren() == 1 && node->ChildAt(0)->IsHidden()) {
2810		node = node->ChildAt(0);
2811		child = node->NodeChild();
2812	}
2813
2814	int32 handlerCount = TypeHandlerRoster::Default()->CountTypeHandlers(
2815		child->GetType());
2816	if (handlerCount > 1) {
2817		TypeHandler* lastHandler = node->GetTypeHandler();
2818		BMenu* handlerMenu = new(std::nothrow) BMenu("Show as");
2819		if (handlerMenu == NULL)
2820			return B_NO_MEMORY;
2821
2822		ObjectDeleter<BMenu> menuDeleter(handlerMenu);
2823		ActionMenuItem* menuItem = new(std::nothrow) ActionMenuItem(
2824			handlerMenu);
2825		if (menuItem == NULL)
2826			return B_NO_MEMORY;
2827		ObjectDeleter<ActionMenuItem> menuItemDeleter(menuItem);
2828		menuDeleter.Detach();
2829
2830		ActionMenuItem* item = NULL;
2831		status_t result = _CreateContextAction("Automatic",
2832			MSG_USE_AUTOMATIC_HANDLER, item);
2833		if (item == NULL)
2834			return B_NO_MEMORY;
2835		item->Message()->AddPointer("node", node);
2836
2837		ObjectDeleter<ActionMenuItem> itemDeleter(item);
2838		if (!handlerMenu->AddItem(item) || !handlerMenu->AddSeparatorItem())
2839			return B_NO_MEMORY;
2840
2841		itemDeleter.Detach();
2842		if (lastHandler == NULL)
2843			item->SetMarked(true);
2844
2845		TypeHandlerList* handlers = NULL;
2846		result = TypeHandlerRoster::Default()->FindTypeHandlers(child,
2847			child->GetType(), handlers);
2848		if (result != B_OK)
2849			return result;
2850
2851		ObjectDeleter<TypeHandlerList> listDeleter(handlers);
2852		while (handlers->CountItems() > 0) {
2853			TypeHandler* handler = handlers->ItemAt(0);
2854			BMessage* message = new(std::nothrow) BMessage(
2855				MSG_USE_EXPLICIT_HANDLER);
2856			if (message == NULL) {
2857				result = B_NO_MEMORY;
2858				break;
2859			}
2860			message->AddPointer("node", node);
2861
2862			TypeHandlerMenuItem* typeItem
2863				= new(std::nothrow) TypeHandlerMenuItem(handler->Name(),
2864					message);
2865			if (typeItem == NULL) {
2866				result = B_NO_MEMORY;
2867				break;
2868			}
2869			ObjectDeleter<TypeHandlerMenuItem> typeItemDeleter(typeItem);
2870
2871			result = typeItem->SetTypeHandler(handler);
2872			if (result != B_OK)
2873				break;
2874			handlers->RemoveItemAt(0);
2875			if (!handlerMenu->AddItem(typeItem)) {
2876				result = B_NO_MEMORY;
2877				break;
2878			}
2879
2880			typeItemDeleter.Detach();
2881			if (handler == lastHandler)
2882				typeItem->SetMarked(true);
2883		}
2884
2885		if (result != B_OK) {
2886			for (int32 i = 0; TypeHandler* handler = handlers->ItemAt(i);
2887				i++) {
2888				handler->ReleaseReference();
2889			}
2890
2891			return result;
2892		}
2893
2894		if (!actions->AddItem(menuItem))
2895			return B_NO_MEMORY;
2896
2897		handlerMenu->SetTargetForItems(this);
2898		menuItemDeleter.Detach();
2899	}
2900
2901	return B_OK;
2902}
2903
2904
2905void
2906VariablesView::_FinishContextMenu(bool force)
2907{
2908	if (fTableCellContextMenuTracker != NULL) {
2909		if (!fTableCellContextMenuTracker->FinishMenu(force) || force) {
2910			fTableCellContextMenuTracker->ReleaseReference();
2911			fTableCellContextMenuTracker = NULL;
2912		}
2913	}
2914}
2915
2916
2917
2918void
2919VariablesView::_SaveViewState(bool updateValues) const
2920{
2921	if (fThread == NULL || fStackFrame == NULL
2922		|| fStackFrame->Function() == NULL) {
2923		return;
2924	}
2925
2926	// get the function ID
2927	FunctionID* functionID = fStackFrame->Function()->GetFunctionID();
2928	if (functionID == NULL)
2929		return;
2930	BReference<FunctionID> functionIDReference(functionID, true);
2931
2932	StackFrameValues* values = NULL;
2933	ExpressionValues* expressionValues = NULL;
2934	BReference<StackFrameValues> valuesReference;
2935	BReference<ExpressionValues> expressionsReference;
2936
2937	if (!updateValues) {
2938		VariablesViewState* viewState = fViewStateHistory->GetState(fThread->ID(),
2939			functionID);
2940		if (viewState != NULL) {
2941			values = viewState->Values();
2942			valuesReference.SetTo(values);
2943
2944			expressionValues = viewState->GetExpressionValues();
2945			expressionsReference.SetTo(expressionValues);
2946		}
2947	}
2948
2949	if (values == NULL) {
2950		values = new(std::nothrow) StackFrameValues;
2951		if (values == NULL)
2952			return;
2953		valuesReference.SetTo(values, true);
2954
2955		if (values->Init() != B_OK)
2956			return;
2957
2958		expressionValues = new(std::nothrow) ExpressionValues;
2959		if (expressionValues == NULL)
2960			return;
2961		expressionsReference.SetTo(expressionValues, true);
2962
2963		if (expressionValues->Init() != B_OK)
2964			return;
2965	}
2966
2967	// create an empty view state
2968	VariablesViewState* viewState = new(std::nothrow) VariablesViewState;
2969	if (viewState == NULL)
2970		return;
2971	BReference<VariablesViewState> viewStateReference(viewState, true);
2972
2973	if (viewState->Init() != B_OK)
2974		return;
2975
2976	viewState->SetValues(values);
2977	viewState->SetExpressionValues(expressionValues);
2978
2979	// populate it
2980	TreeTablePath path;
2981	if (_AddViewStateDescendentNodeInfos(viewState,
2982			fVariableTableModel->Root(), path, updateValues) != B_OK) {
2983		return;
2984	}
2985
2986	// add the view state to the history
2987	fViewStateHistory->SetState(fThread->ID(), functionID, viewState);
2988}
2989
2990
2991void
2992VariablesView::_RestoreViewState()
2993{
2994	if (fPreviousViewState != NULL) {
2995		fPreviousViewState->ReleaseReference();
2996		fPreviousViewState = NULL;
2997	}
2998
2999	if (fThread == NULL || fStackFrame == NULL
3000		|| fStackFrame->Function() == NULL) {
3001		return;
3002	}
3003
3004	// get the function ID
3005	FunctionID* functionID = fStackFrame->Function()->GetFunctionID();
3006	if (functionID == NULL)
3007		return;
3008	BReference<FunctionID> functionIDReference(functionID, true);
3009
3010	// get the previous view state
3011	VariablesViewState* viewState = fViewStateHistory->GetState(fThread->ID(),
3012		functionID);
3013	if (viewState == NULL)
3014		return;
3015
3016	// apply the view state
3017	TreeTablePath path;
3018	_ApplyViewStateDescendentNodeInfos(viewState, fVariableTableModel->Root(),
3019		path);
3020}
3021
3022
3023status_t
3024VariablesView::_AddViewStateDescendentNodeInfos(VariablesViewState* viewState,
3025	void* parent, TreeTablePath& path, bool updateValues) const
3026{
3027	bool isRoot = parent == fVariableTableModel->Root();
3028	int32 childCount = isRoot ? fVariableTableModel->CountChildren(parent)
3029			: ((ModelNode*)parent)->CountChildren();
3030	for (int32 i = 0; i < childCount; i++) {
3031		ModelNode* node = (ModelNode*)(isRoot ? fVariableTableModel->ChildAt(
3032					parent, i)
3033				: ((ModelNode*)parent)->ChildAt(i));
3034
3035		if (!path.AddComponent(i))
3036			return B_NO_MEMORY;
3037
3038		// add the node's info
3039		VariablesViewNodeInfo nodeInfo;
3040		nodeInfo.SetNodeExpanded(fVariableTable->IsNodeExpanded(path));
3041		nodeInfo.SetCastedType(node->GetCastedType());
3042		nodeInfo.SetTypeHandler(node->GetTypeHandler());
3043		TableCellValueRenderer* renderer = node->TableCellRenderer();
3044		if (renderer != NULL) {
3045			Settings* settings = renderer->GetSettings();
3046			if (settings != NULL)
3047				nodeInfo.SetRendererSettings(settings->Message());
3048		}
3049
3050		Value* value = node->GetValue();
3051		Variable* variable = node->GetVariable();
3052		TypeComponentPath* componentPath = node->GetPath();
3053		ObjectID* id = variable->ID();
3054
3055		status_t error = viewState->SetNodeInfo(id, componentPath, nodeInfo);
3056		if (error != B_OK)
3057			return error;
3058
3059		if (value != NULL && updateValues) {
3060			BVariant variableValueData;
3061			if (value->ToVariant(variableValueData))
3062				error = viewState->Values()->SetValue(id, componentPath,
3063					variableValueData);
3064			if (error != B_OK)
3065				return error;
3066		}
3067
3068		// recurse
3069		error = _AddViewStateDescendentNodeInfos(viewState, node, path,
3070			updateValues);
3071		if (error != B_OK)
3072			return error;
3073
3074		path.RemoveLastComponent();
3075	}
3076
3077	return B_OK;
3078}
3079
3080
3081status_t
3082VariablesView::_ApplyViewStateDescendentNodeInfos(VariablesViewState* viewState,
3083	void* parent, TreeTablePath& path)
3084{
3085	bool isRoot = parent == fVariableTableModel->Root();
3086	int32 childCount = isRoot ? fVariableTableModel->CountChildren(parent)
3087			: ((ModelNode*)parent)->CountChildren();
3088	for (int32 i = 0; i < childCount; i++) {
3089		ModelNode* node = (ModelNode*)(isRoot ? fVariableTableModel->ChildAt(
3090					parent, i)
3091				: ((ModelNode*)parent)->ChildAt(i));
3092		if (!path.AddComponent(i))
3093			return B_NO_MEMORY;
3094
3095		// apply the node's info, if any
3096		ObjectID* objectID = node->GetVariable()->ID();
3097		TypeComponentPath* componentPath = node->GetPath();
3098		const VariablesViewNodeInfo* nodeInfo = viewState->GetNodeInfo(
3099			objectID, componentPath);
3100		if (nodeInfo != NULL) {
3101			// NB: if the node info indicates that the node in question
3102			// was being cast to a different type, this *must* be applied
3103			// before any other view state restoration, since it
3104			// potentially changes the child hierarchy under that node.
3105			Type* type = nodeInfo->GetCastedType();
3106			TypeHandler* handler = nodeInfo->GetTypeHandler();
3107			node->SetCastedType(type);
3108			node->SetTypeHandler(handler);
3109			if (type != NULL || handler != NULL) {
3110				if (type == NULL)
3111					type = node->GetType();
3112				ValueNode* valueNode = NULL;
3113				if (TypeHandlerRoster::Default()->CreateValueNode(
3114					node->NodeChild(), type, handler, valueNode) == B_OK) {
3115					node->NodeChild()->SetNode(valueNode);
3116				}
3117			}
3118
3119			// we don't have a renderer yet so we can't apply the settings
3120			// at this stage. Store them on the model node so we can lazily
3121			// apply them once the value is retrieved.
3122			node->SetLastRendererSettings(nodeInfo->GetRendererSettings());
3123
3124			fVariableTable->SetNodeExpanded(path,
3125				nodeInfo->IsNodeExpanded());
3126
3127			BVariant previousValue;
3128			if (viewState->Values()->GetValue(objectID, componentPath,
3129				previousValue)) {
3130				node->SetPreviousValue(previousValue);
3131			}
3132		}
3133
3134		// recurse
3135		status_t error = _ApplyViewStateDescendentNodeInfos(viewState, node,
3136			path);
3137		if (error != B_OK)
3138			return error;
3139
3140		path.RemoveLastComponent();
3141	}
3142
3143	return B_OK;
3144}
3145
3146
3147void
3148VariablesView::_CopyVariableValueToClipboard()
3149{
3150	ModelNode* node = reinterpret_cast<ModelNode*>(
3151		fVariableTable->SelectionModel()->NodeAt(0));
3152
3153	Value* value = node->GetValue();
3154	BString valueData;
3155	if (value != NULL && value->ToString(valueData)) {
3156		be_clipboard->Lock();
3157		be_clipboard->Data()->RemoveData("text/plain");
3158		be_clipboard->Data()->AddData ("text/plain",
3159			B_MIME_TYPE, valueData.String(),
3160			valueData.Length());
3161		be_clipboard->Commit();
3162		be_clipboard->Unlock();
3163	}
3164}
3165
3166
3167status_t
3168VariablesView::_AddExpression(const char* expression,
3169	bool persistentExpression, ExpressionInfo*& _info)
3170{
3171	ExpressionInfoEntry* entry = NULL;
3172	if (persistentExpression) {
3173		// if our stack frame doesn't have an associated function,
3174		// we can't add an expression
3175		FunctionInstance* function = fStackFrame->Function();
3176		if (function == NULL)
3177			return B_NOT_ALLOWED;
3178
3179		FunctionID* id = function->GetFunctionID();
3180		if (id == NULL)
3181			return B_NO_MEMORY;
3182
3183		BReference<FunctionID> idReference(id, true);
3184
3185		entry = fExpressions->Lookup(FunctionKey(id));
3186		if (entry == NULL) {
3187			entry = new(std::nothrow) ExpressionInfoEntry(id);
3188			if (entry == NULL)
3189				return B_NO_MEMORY;
3190			status_t error = fExpressions->Insert(entry);
3191			if (error != B_OK) {
3192				delete entry;
3193				return error;
3194			}
3195		}
3196	}
3197
3198	ExpressionInfo* info = new(std::nothrow) ExpressionInfo(expression);
3199
3200	if (info == NULL)
3201		return B_NO_MEMORY;
3202
3203	BReference<ExpressionInfo> infoReference(info, true);
3204
3205	if (persistentExpression) {
3206		if (!entry->AddItem(info))
3207			return B_NO_MEMORY;
3208	} else
3209		fTemporaryExpression = info;
3210
3211	info->AddListener(this);
3212	infoReference.Detach();
3213	_info = info;
3214	return B_OK;
3215}
3216
3217
3218void
3219VariablesView::_RemoveExpression(ModelNode* node)
3220{
3221	if (!fExpressionChildren.HasItem(node->NodeChild()))
3222		return;
3223
3224	FunctionID* id = fStackFrame->Function()->GetFunctionID();
3225	BReference<FunctionID> idReference(id, true);
3226
3227	ExpressionInfoEntry* entry = fExpressions->Lookup(FunctionKey(id));
3228	if (entry == NULL)
3229		return;
3230
3231	for (int32 i = 0; i < entry->CountItems(); i++) {
3232		ExpressionInfo* info = entry->ItemAt(i);
3233		if (info->Expression() == node->Name()) {
3234			entry->RemoveItemAt(i);
3235			info->RemoveListener(this);
3236			info->ReleaseReference();
3237			break;
3238		}
3239	}
3240
3241	fVariableTableModel->RemoveSyntheticNode(node);
3242}
3243
3244
3245void
3246VariablesView::_RestoreExpressionNodes()
3247{
3248	FunctionInstance* instance = fStackFrame->Function();
3249	if (instance == NULL)
3250		return;
3251
3252	FunctionID* id = instance->GetFunctionID();
3253	if (id == NULL)
3254		return;
3255
3256	BReference<FunctionID> idReference(id, true);
3257
3258	ExpressionInfoEntry* entry = fExpressions->Lookup(FunctionKey(id));
3259	if (entry == NULL)
3260		return;
3261
3262	for (int32 i = 0; i < entry->CountItems(); i++) {
3263		ExpressionInfo* info = entry->ItemAt(i);
3264		fListener->ExpressionEvaluationRequested(info, fStackFrame, fThread);
3265	}
3266}
3267
3268
3269void
3270VariablesView::_AddExpressionNode(ExpressionInfo* info, status_t result,
3271	ExpressionResult* value)
3272{
3273	bool temporaryExpression = (info == fTemporaryExpression);
3274	Variable* variable = NULL;
3275	BReference<Variable> variableReference;
3276	BVariant valueData;
3277
3278	ExpressionVariableID* id
3279		= new(std::nothrow) ExpressionVariableID(info);
3280	if (id == NULL)
3281		return;
3282	BReference<ObjectID> idReference(id, true);
3283
3284	Type* type = NULL;
3285	ValueLocation* location = NULL;
3286	ValueNodeChild* child = NULL;
3287	BReference<Type> typeReference;
3288	BReference<ValueLocation> locationReference;
3289	if (value->Kind() == EXPRESSION_RESULT_KIND_PRIMITIVE) {
3290		value->PrimitiveValue()->ToVariant(valueData);
3291		if (_GetTypeForTypeCode(valueData.Type(), type) != B_OK)
3292			return;
3293		typeReference.SetTo(type, true);
3294
3295		location = new(std::nothrow) ValueLocation();
3296		if (location == NULL)
3297			return;
3298		locationReference.SetTo(location, true);
3299
3300		if (valueData.IsNumber()) {
3301
3302			ValuePieceLocation piece;
3303			if (!piece.SetToValue(valueData.Bytes(), valueData.Size())
3304				|| !location->AddPiece(piece)) {
3305				return;
3306			}
3307		}
3308	} else if (value->Kind() == EXPRESSION_RESULT_KIND_VALUE_NODE) {
3309		child = value->ValueNodeValue();
3310		type = child->GetType();
3311		typeReference.SetTo(type);
3312		location = child->Location();
3313		locationReference.SetTo(location);
3314	}
3315
3316	variable = new(std::nothrow) Variable(id,
3317		info->Expression(), type, location);
3318	if (variable == NULL)
3319		return;
3320	variableReference.SetTo(variable, true);
3321
3322	status_t error = fVariableTableModel->AddSyntheticNode(variable, child,
3323		info->Expression());
3324	if (error != B_OK)
3325		return;
3326
3327	// In the case of either an evaluation error, or an unsupported result
3328	// type, set an explanatory string for the result directly.
3329	if (result != B_OK || valueData.Type() == B_STRING_TYPE) {
3330		StringValue* explicitValue = new(std::nothrow) StringValue(
3331			valueData.ToString());
3332		if (explicitValue == NULL)
3333			return;
3334
3335		child->Node()->SetLocationAndValue(NULL, explicitValue, B_OK);
3336	}
3337
3338	if (temporaryExpression || fExpressionChildren.AddItem(child)) {
3339		child->AcquireReference();
3340
3341		if (temporaryExpression)
3342			return;
3343
3344		// attempt to restore our newly added node's view state,
3345		// if applicable.
3346		FunctionID* functionID = fStackFrame->Function()
3347			->GetFunctionID();
3348		if (functionID == NULL)
3349			return;
3350		BReference<FunctionID> functionIDReference(functionID,
3351			true);
3352		VariablesViewState* viewState = fViewStateHistory
3353			->GetState(fThread->ID(), functionID);
3354		if (viewState != NULL) {
3355			TreeTablePath path;
3356			_ApplyViewStateDescendentNodeInfos(viewState,
3357				fVariableTableModel->Root(), path);
3358		}
3359	}
3360}
3361
3362
3363void
3364VariablesView::_HandleTypecastResult(status_t result, ExpressionResult* value)
3365{
3366	BString errorMessage;
3367	if (value == NULL) {
3368		errorMessage.SetToFormat("Failed to evaluate expression \"%s\": %s (%"
3369			B_PRId32 ")", fPendingTypecastInfo->Expression().String(),
3370			strerror(result), result);
3371	} else if (result != B_OK) {
3372		BVariant valueData;
3373		value->PrimitiveValue()->ToVariant(valueData);
3374
3375		// usually, the evaluation can give us back an error message to
3376		// specifically indicate why it failed. If it did, simply use
3377		// the message directly, otherwise fall back to generating an error
3378		// message based on the error code
3379		if (valueData.Type() == B_STRING_TYPE)
3380			errorMessage = valueData.ToString();
3381		else {
3382			errorMessage.SetToFormat("Failed to evaluate expression \"%s\":"
3383				" %s (%" B_PRId32 ")",
3384				fPendingTypecastInfo->Expression().String(), strerror(result),
3385				result);
3386		}
3387
3388	} else if (value->Kind() != EXPRESSION_RESULT_KIND_TYPE) {
3389		errorMessage.SetToFormat("Expression \"%s\" does not evaluate to a"
3390			" type.", fPendingTypecastInfo->Expression().String());
3391	}
3392
3393	if (!errorMessage.IsEmpty()) {
3394		BAlert* alert = new(std::nothrow) BAlert("Typecast error",
3395			errorMessage, "Close");
3396		if (alert != NULL)
3397			alert->Go();
3398
3399		return;
3400	}
3401
3402	Type* type = value->GetType();
3403	BReference<Type> typeRef(type);
3404	ValueNode* valueNode = NULL;
3405	ModelNode* node = fPendingTypecastInfo->TargetNode();
3406	if (TypeHandlerRoster::Default()->CreateValueNode(node->NodeChild(), type,
3407			NULL, valueNode) != B_OK) {
3408		return;
3409	}
3410
3411	node->NodeChild()->SetNode(valueNode);
3412	node->SetCastedType(type);
3413	fVariableTableModel->NotifyNodeChanged(node);
3414}
3415
3416
3417void
3418VariablesView::_HandleEditVariableRequest(ModelNode* node, Value* value)
3419{
3420	// get a value handler
3421	ValueHandler* valueHandler;
3422	status_t error = ValueHandlerRoster::Default()->FindValueHandler(value,
3423		valueHandler);
3424	if (error != B_OK)
3425		return;
3426
3427	ValueNode* valueNode = node->NodeChild()->Node();
3428
3429	BReference<ValueHandler> handlerReference(valueHandler, true);
3430	TableCellValueRenderer* renderer = node->TableCellRenderer();
3431	TableCellValueEditor* editor = NULL;
3432	error = valueHandler->GetTableCellValueEditor(value,
3433		renderer != NULL ? renderer->GetSettings() : NULL, editor);
3434	if (error != B_OK || editor == NULL)
3435		return;
3436
3437	BReference<TableCellValueEditor> editorReference(editor, true);
3438
3439	try {
3440		fEditWindow = VariableEditWindow::Create(value, valueNode, editor,
3441			this);
3442	} catch (...) {
3443		fEditWindow = NULL;
3444		return;
3445	}
3446
3447	fEditWindow->Show();
3448}
3449
3450
3451status_t
3452VariablesView::_GetTypeForTypeCode(int32 type, Type*& _resultType) const
3453{
3454	if (BVariant::TypeIsNumber(type) || type == B_STRING_TYPE) {
3455		_resultType = new(std::nothrow) SyntheticPrimitiveType(type);
3456		if (_resultType == NULL)
3457			return B_NO_MEMORY;
3458
3459		return B_OK;
3460	}
3461
3462	return B_NOT_SUPPORTED;
3463}
3464
3465
3466// #pragma mark - Listener
3467
3468
3469VariablesView::Listener::~Listener()
3470{
3471}
3472