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