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