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