xref: /haiku/src/apps/debugger/user_interface/gui/team_window/VariablesView.cpp (revision cbe0a0c436162d78cc3f92a305b64918c839d079)
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 = reinterpret_cast<addr_t>(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 	if (node->CountChildren() == 1 && node->ChildAt(0)->IsHidden()) {
2804 		node = node->ChildAt(0);
2805 		child = node->NodeChild();
2806 	}
2807 
2808 	int32 handlerCount = TypeHandlerRoster::Default()->CountTypeHandlers(
2809 		child->GetType());
2810 	if (handlerCount > 1) {
2811 		TypeHandler* lastHandler = node->GetTypeHandler();
2812 		BMenu* handlerMenu = new(std::nothrow) BMenu("Show as");
2813 		if (handlerMenu == NULL)
2814 			return B_NO_MEMORY;
2815 
2816 		ObjectDeleter<BMenu> menuDeleter(handlerMenu);
2817 		ActionMenuItem* menuItem = new(std::nothrow) ActionMenuItem(
2818 			handlerMenu);
2819 		if (menuItem == NULL)
2820 			return B_NO_MEMORY;
2821 		ObjectDeleter<ActionMenuItem> menuItemDeleter(menuItem);
2822 		menuDeleter.Detach();
2823 
2824 		ActionMenuItem* item = NULL;
2825 		status_t result = _CreateContextAction("Automatic",
2826 			MSG_USE_AUTOMATIC_HANDLER, item);
2827 		if (item == NULL)
2828 			return B_NO_MEMORY;
2829 		item->Message()->AddPointer("node", node);
2830 
2831 		ObjectDeleter<ActionMenuItem> itemDeleter(item);
2832 		if (!handlerMenu->AddItem(item) || !handlerMenu->AddSeparatorItem())
2833 			return B_NO_MEMORY;
2834 
2835 		itemDeleter.Detach();
2836 		if (lastHandler == NULL)
2837 			item->SetMarked(true);
2838 
2839 		TypeHandlerList* handlers = NULL;
2840 		result = TypeHandlerRoster::Default()->FindTypeHandlers(child,
2841 			child->GetType(), handlers);
2842 		if (result != B_OK)
2843 			return result;
2844 
2845 		ObjectDeleter<TypeHandlerList> listDeleter(handlers);
2846 		while (handlers->CountItems() > 0) {
2847 			TypeHandler* handler = handlers->ItemAt(0);
2848 			BMessage* message = new(std::nothrow) BMessage(
2849 				MSG_USE_EXPLICIT_HANDLER);
2850 			if (message == NULL) {
2851 				result = B_NO_MEMORY;
2852 				break;
2853 			}
2854 			message->AddPointer("node", node);
2855 
2856 			TypeHandlerMenuItem* typeItem
2857 				= new(std::nothrow) TypeHandlerMenuItem(handler->Name(),
2858 					message);
2859 			if (typeItem == NULL) {
2860 				result = B_NO_MEMORY;
2861 				break;
2862 			}
2863 			ObjectDeleter<TypeHandlerMenuItem> typeItemDeleter(typeItem);
2864 
2865 			result = typeItem->SetTypeHandler(handler);
2866 			if (result != B_OK)
2867 				break;
2868 			handlers->RemoveItemAt(0);
2869 			if (!handlerMenu->AddItem(typeItem)) {
2870 				result = B_NO_MEMORY;
2871 				break;
2872 			}
2873 
2874 			typeItemDeleter.Detach();
2875 			if (handler == lastHandler)
2876 				typeItem->SetMarked(true);
2877 		}
2878 
2879 		if (result != B_OK) {
2880 			for (int32 i = 0; TypeHandler* handler = handlers->ItemAt(i);
2881 				i++) {
2882 				handler->ReleaseReference();
2883 			}
2884 
2885 			return result;
2886 		}
2887 
2888 		if (!actions->AddItem(menuItem))
2889 			return B_NO_MEMORY;
2890 
2891 		handlerMenu->SetTargetForItems(this);
2892 		menuItemDeleter.Detach();
2893 	}
2894 
2895 	return B_OK;
2896 }
2897 
2898 
2899 void
2900 VariablesView::_FinishContextMenu(bool force)
2901 {
2902 	if (fTableCellContextMenuTracker != NULL) {
2903 		if (!fTableCellContextMenuTracker->FinishMenu(force) || force) {
2904 			fTableCellContextMenuTracker->ReleaseReference();
2905 			fTableCellContextMenuTracker = NULL;
2906 		}
2907 	}
2908 }
2909 
2910 
2911 
2912 void
2913 VariablesView::_SaveViewState(bool updateValues) const
2914 {
2915 	if (fThread == NULL || fStackFrame == NULL
2916 		|| fStackFrame->Function() == NULL) {
2917 		return;
2918 	}
2919 
2920 	// get the function ID
2921 	FunctionID* functionID = fStackFrame->Function()->GetFunctionID();
2922 	if (functionID == NULL)
2923 		return;
2924 	BReference<FunctionID> functionIDReference(functionID, true);
2925 
2926 	StackFrameValues* values = NULL;
2927 	ExpressionValues* expressionValues = NULL;
2928 	BReference<StackFrameValues> valuesReference;
2929 	BReference<ExpressionValues> expressionsReference;
2930 
2931 	if (!updateValues) {
2932 		VariablesViewState* viewState = fViewStateHistory->GetState(fThread->ID(),
2933 			functionID);
2934 		if (viewState != NULL) {
2935 			values = viewState->Values();
2936 			valuesReference.SetTo(values);
2937 
2938 			expressionValues = viewState->GetExpressionValues();
2939 			expressionsReference.SetTo(expressionValues);
2940 		}
2941 	}
2942 
2943 	if (values == NULL) {
2944 		values = new(std::nothrow) StackFrameValues;
2945 		if (values == NULL)
2946 			return;
2947 		valuesReference.SetTo(values, true);
2948 
2949 		if (values->Init() != B_OK)
2950 			return;
2951 
2952 		expressionValues = new(std::nothrow) ExpressionValues;
2953 		if (expressionValues == NULL)
2954 			return;
2955 		expressionsReference.SetTo(expressionValues, true);
2956 
2957 		if (expressionValues->Init() != B_OK)
2958 			return;
2959 	}
2960 
2961 	// create an empty view state
2962 	VariablesViewState* viewState = new(std::nothrow) VariablesViewState;
2963 	if (viewState == NULL)
2964 		return;
2965 	BReference<VariablesViewState> viewStateReference(viewState, true);
2966 
2967 	if (viewState->Init() != B_OK)
2968 		return;
2969 
2970 	viewState->SetValues(values);
2971 	viewState->SetExpressionValues(expressionValues);
2972 
2973 	// populate it
2974 	TreeTablePath path;
2975 	if (_AddViewStateDescendentNodeInfos(viewState,
2976 			fVariableTableModel->Root(), path, updateValues) != B_OK) {
2977 		return;
2978 	}
2979 
2980 	// add the view state to the history
2981 	fViewStateHistory->SetState(fThread->ID(), functionID, viewState);
2982 }
2983 
2984 
2985 void
2986 VariablesView::_RestoreViewState()
2987 {
2988 	if (fPreviousViewState != NULL) {
2989 		fPreviousViewState->ReleaseReference();
2990 		fPreviousViewState = NULL;
2991 	}
2992 
2993 	if (fThread == NULL || fStackFrame == NULL
2994 		|| fStackFrame->Function() == NULL) {
2995 		return;
2996 	}
2997 
2998 	// get the function ID
2999 	FunctionID* functionID = fStackFrame->Function()->GetFunctionID();
3000 	if (functionID == NULL)
3001 		return;
3002 	BReference<FunctionID> functionIDReference(functionID, true);
3003 
3004 	// get the previous view state
3005 	VariablesViewState* viewState = fViewStateHistory->GetState(fThread->ID(),
3006 		functionID);
3007 	if (viewState == NULL)
3008 		return;
3009 
3010 	// apply the view state
3011 	TreeTablePath path;
3012 	_ApplyViewStateDescendentNodeInfos(viewState, fVariableTableModel->Root(),
3013 		path);
3014 }
3015 
3016 
3017 status_t
3018 VariablesView::_AddViewStateDescendentNodeInfos(VariablesViewState* viewState,
3019 	void* parent, TreeTablePath& path, bool updateValues) const
3020 {
3021 	bool isRoot = parent == fVariableTableModel->Root();
3022 	int32 childCount = isRoot ? fVariableTableModel->CountChildren(parent)
3023 			: ((ModelNode*)parent)->CountChildren();
3024 	for (int32 i = 0; i < childCount; i++) {
3025 		ModelNode* node = (ModelNode*)(isRoot ? fVariableTableModel->ChildAt(
3026 					parent, i)
3027 				: ((ModelNode*)parent)->ChildAt(i));
3028 
3029 		if (!path.AddComponent(i))
3030 			return B_NO_MEMORY;
3031 
3032 		// add the node's info
3033 		VariablesViewNodeInfo nodeInfo;
3034 		nodeInfo.SetNodeExpanded(fVariableTable->IsNodeExpanded(path));
3035 		nodeInfo.SetCastedType(node->GetCastedType());
3036 		nodeInfo.SetTypeHandler(node->GetTypeHandler());
3037 		TableCellValueRenderer* renderer = node->TableCellRenderer();
3038 		if (renderer != NULL) {
3039 			Settings* settings = renderer->GetSettings();
3040 			if (settings != NULL)
3041 				nodeInfo.SetRendererSettings(settings->Message());
3042 		}
3043 
3044 		Value* value = node->GetValue();
3045 		Variable* variable = node->GetVariable();
3046 		TypeComponentPath* componentPath = node->GetPath();
3047 		ObjectID* id = variable->ID();
3048 
3049 		status_t error = viewState->SetNodeInfo(id, componentPath, nodeInfo);
3050 		if (error != B_OK)
3051 			return error;
3052 
3053 		if (value != NULL && updateValues) {
3054 			BVariant variableValueData;
3055 			if (value->ToVariant(variableValueData))
3056 				error = viewState->Values()->SetValue(id, componentPath,
3057 					variableValueData);
3058 			if (error != B_OK)
3059 				return error;
3060 		}
3061 
3062 		// recurse
3063 		error = _AddViewStateDescendentNodeInfos(viewState, node, path,
3064 			updateValues);
3065 		if (error != B_OK)
3066 			return error;
3067 
3068 		path.RemoveLastComponent();
3069 	}
3070 
3071 	return B_OK;
3072 }
3073 
3074 
3075 status_t
3076 VariablesView::_ApplyViewStateDescendentNodeInfos(VariablesViewState* viewState,
3077 	void* parent, TreeTablePath& path)
3078 {
3079 	bool isRoot = parent == fVariableTableModel->Root();
3080 	int32 childCount = isRoot ? fVariableTableModel->CountChildren(parent)
3081 			: ((ModelNode*)parent)->CountChildren();
3082 	for (int32 i = 0; i < childCount; i++) {
3083 		ModelNode* node = (ModelNode*)(isRoot ? fVariableTableModel->ChildAt(
3084 					parent, i)
3085 				: ((ModelNode*)parent)->ChildAt(i));
3086 		if (!path.AddComponent(i))
3087 			return B_NO_MEMORY;
3088 
3089 		// apply the node's info, if any
3090 		ObjectID* objectID = node->GetVariable()->ID();
3091 		TypeComponentPath* componentPath = node->GetPath();
3092 		const VariablesViewNodeInfo* nodeInfo = viewState->GetNodeInfo(
3093 			objectID, componentPath);
3094 		if (nodeInfo != NULL) {
3095 			// NB: if the node info indicates that the node in question
3096 			// was being cast to a different type, this *must* be applied
3097 			// before any other view state restoration, since it
3098 			// potentially changes the child hierarchy under that node.
3099 			Type* type = nodeInfo->GetCastedType();
3100 			TypeHandler* handler = nodeInfo->GetTypeHandler();
3101 			node->SetCastedType(type);
3102 			node->SetTypeHandler(handler);
3103 			if (type != NULL || handler != NULL) {
3104 				if (type == NULL)
3105 					type = node->GetType();
3106 				ValueNode* valueNode = NULL;
3107 				if (TypeHandlerRoster::Default()->CreateValueNode(
3108 					node->NodeChild(), type, handler, valueNode) == B_OK) {
3109 					node->NodeChild()->SetNode(valueNode);
3110 				}
3111 			}
3112 
3113 			// we don't have a renderer yet so we can't apply the settings
3114 			// at this stage. Store them on the model node so we can lazily
3115 			// apply them once the value is retrieved.
3116 			node->SetLastRendererSettings(nodeInfo->GetRendererSettings());
3117 
3118 			fVariableTable->SetNodeExpanded(path,
3119 				nodeInfo->IsNodeExpanded());
3120 
3121 			BVariant previousValue;
3122 			if (viewState->Values()->GetValue(objectID, componentPath,
3123 				previousValue)) {
3124 				node->SetPreviousValue(previousValue);
3125 			}
3126 		}
3127 
3128 		// recurse
3129 		status_t error = _ApplyViewStateDescendentNodeInfos(viewState, node,
3130 			path);
3131 		if (error != B_OK)
3132 			return error;
3133 
3134 		path.RemoveLastComponent();
3135 	}
3136 
3137 	return B_OK;
3138 }
3139 
3140 
3141 void
3142 VariablesView::_CopyVariableValueToClipboard()
3143 {
3144 	ModelNode* node = reinterpret_cast<ModelNode*>(
3145 		fVariableTable->SelectionModel()->NodeAt(0));
3146 
3147 	Value* value = node->GetValue();
3148 	BString valueData;
3149 	if (value != NULL && value->ToString(valueData)) {
3150 		be_clipboard->Lock();
3151 		be_clipboard->Data()->RemoveData("text/plain");
3152 		be_clipboard->Data()->AddData ("text/plain",
3153 			B_MIME_TYPE, valueData.String(),
3154 			valueData.Length());
3155 		be_clipboard->Commit();
3156 		be_clipboard->Unlock();
3157 	}
3158 }
3159 
3160 
3161 status_t
3162 VariablesView::_AddExpression(const char* expression,
3163 	bool persistentExpression, ExpressionInfo*& _info)
3164 {
3165 	ExpressionInfoEntry* entry = NULL;
3166 	if (persistentExpression) {
3167 		// if our stack frame doesn't have an associated function,
3168 		// we can't add an expression
3169 		FunctionInstance* function = fStackFrame->Function();
3170 		if (function == NULL)
3171 			return B_NOT_ALLOWED;
3172 
3173 		FunctionID* id = function->GetFunctionID();
3174 		if (id == NULL)
3175 			return B_NO_MEMORY;
3176 
3177 		BReference<FunctionID> idReference(id, true);
3178 
3179 		entry = fExpressions->Lookup(FunctionKey(id));
3180 		if (entry == NULL) {
3181 			entry = new(std::nothrow) ExpressionInfoEntry(id);
3182 			if (entry == NULL)
3183 				return B_NO_MEMORY;
3184 			status_t error = fExpressions->Insert(entry);
3185 			if (error != B_OK) {
3186 				delete entry;
3187 				return error;
3188 			}
3189 		}
3190 	}
3191 
3192 	ExpressionInfo* info = new(std::nothrow) ExpressionInfo(expression);
3193 
3194 	if (info == NULL)
3195 		return B_NO_MEMORY;
3196 
3197 	BReference<ExpressionInfo> infoReference(info, true);
3198 
3199 	if (persistentExpression) {
3200 		if (!entry->AddItem(info))
3201 			return B_NO_MEMORY;
3202 	} else
3203 		fTemporaryExpression = info;
3204 
3205 	info->AddListener(this);
3206 	infoReference.Detach();
3207 	_info = info;
3208 	return B_OK;
3209 }
3210 
3211 
3212 void
3213 VariablesView::_RemoveExpression(ModelNode* node)
3214 {
3215 	if (!fExpressionChildren.HasItem(node->NodeChild()))
3216 		return;
3217 
3218 	FunctionID* id = fStackFrame->Function()->GetFunctionID();
3219 	BReference<FunctionID> idReference(id, true);
3220 
3221 	ExpressionInfoEntry* entry = fExpressions->Lookup(FunctionKey(id));
3222 	if (entry == NULL)
3223 		return;
3224 
3225 	for (int32 i = 0; i < entry->CountItems(); i++) {
3226 		ExpressionInfo* info = entry->ItemAt(i);
3227 		if (info->Expression() == node->Name()) {
3228 			entry->RemoveItemAt(i);
3229 			info->RemoveListener(this);
3230 			info->ReleaseReference();
3231 			break;
3232 		}
3233 	}
3234 
3235 	fVariableTableModel->RemoveSyntheticNode(node);
3236 }
3237 
3238 
3239 void
3240 VariablesView::_RestoreExpressionNodes()
3241 {
3242 	FunctionInstance* instance = fStackFrame->Function();
3243 	if (instance == NULL)
3244 		return;
3245 
3246 	FunctionID* id = instance->GetFunctionID();
3247 	if (id == NULL)
3248 		return;
3249 
3250 	BReference<FunctionID> idReference(id, true);
3251 
3252 	ExpressionInfoEntry* entry = fExpressions->Lookup(FunctionKey(id));
3253 	if (entry == NULL)
3254 		return;
3255 
3256 	for (int32 i = 0; i < entry->CountItems(); i++) {
3257 		ExpressionInfo* info = entry->ItemAt(i);
3258 		fListener->ExpressionEvaluationRequested(info, fStackFrame, fThread);
3259 	}
3260 }
3261 
3262 
3263 void
3264 VariablesView::_AddExpressionNode(ExpressionInfo* info, status_t result,
3265 	ExpressionResult* value)
3266 {
3267 	bool temporaryExpression = (info == fTemporaryExpression);
3268 	Variable* variable = NULL;
3269 	BReference<Variable> variableReference;
3270 	BVariant valueData;
3271 
3272 	ExpressionVariableID* id
3273 		= new(std::nothrow) ExpressionVariableID(info);
3274 	if (id == NULL)
3275 		return;
3276 	BReference<ObjectID> idReference(id, true);
3277 
3278 	Type* type = NULL;
3279 	ValueLocation* location = NULL;
3280 	ValueNodeChild* child = NULL;
3281 	BReference<Type> typeReference;
3282 	BReference<ValueLocation> locationReference;
3283 	if (value->Kind() == EXPRESSION_RESULT_KIND_PRIMITIVE) {
3284 		value->PrimitiveValue()->ToVariant(valueData);
3285 		if (_GetTypeForTypeCode(valueData.Type(), type) != B_OK)
3286 			return;
3287 		typeReference.SetTo(type, true);
3288 
3289 		location = new(std::nothrow) ValueLocation();
3290 		if (location == NULL)
3291 			return;
3292 		locationReference.SetTo(location, true);
3293 
3294 		if (valueData.IsNumber()) {
3295 
3296 			ValuePieceLocation piece;
3297 			if (!piece.SetToValue(valueData.Bytes(), valueData.Size())
3298 				|| !location->AddPiece(piece)) {
3299 				return;
3300 			}
3301 		}
3302 	} else if (value->Kind() == EXPRESSION_RESULT_KIND_VALUE_NODE) {
3303 		child = value->ValueNodeValue();
3304 		type = child->GetType();
3305 		typeReference.SetTo(type);
3306 		location = child->Location();
3307 		locationReference.SetTo(location);
3308 	}
3309 
3310 	variable = new(std::nothrow) Variable(id,
3311 		info->Expression(), type, location);
3312 	if (variable == NULL)
3313 		return;
3314 	variableReference.SetTo(variable, true);
3315 
3316 	status_t error = fVariableTableModel->AddSyntheticNode(variable, child,
3317 		info->Expression());
3318 	if (error != B_OK)
3319 		return;
3320 
3321 	// In the case of either an evaluation error, or an unsupported result
3322 	// type, set an explanatory string for the result directly.
3323 	if (result != B_OK || valueData.Type() == B_STRING_TYPE) {
3324 		StringValue* explicitValue = new(std::nothrow) StringValue(
3325 			valueData.ToString());
3326 		if (explicitValue == NULL)
3327 			return;
3328 
3329 		child->Node()->SetLocationAndValue(NULL, explicitValue, B_OK);
3330 	}
3331 
3332 	if (temporaryExpression || fExpressionChildren.AddItem(child)) {
3333 		child->AcquireReference();
3334 
3335 		if (temporaryExpression)
3336 			return;
3337 
3338 		// attempt to restore our newly added node's view state,
3339 		// if applicable.
3340 		FunctionID* functionID = fStackFrame->Function()
3341 			->GetFunctionID();
3342 		if (functionID == NULL)
3343 			return;
3344 		BReference<FunctionID> functionIDReference(functionID,
3345 			true);
3346 		VariablesViewState* viewState = fViewStateHistory
3347 			->GetState(fThread->ID(), functionID);
3348 		if (viewState != NULL) {
3349 			TreeTablePath path;
3350 			_ApplyViewStateDescendentNodeInfos(viewState,
3351 				fVariableTableModel->Root(), path);
3352 		}
3353 	}
3354 }
3355 
3356 
3357 void
3358 VariablesView::_HandleTypecastResult(status_t result, ExpressionResult* value)
3359 {
3360 	BString errorMessage;
3361 	if (value == NULL) {
3362 		errorMessage.SetToFormat("Failed to evaluate expression \"%s\": %s (%"
3363 			B_PRId32 ")", fPendingTypecastInfo->Expression().String(),
3364 			strerror(result), result);
3365 	} else if (result != B_OK) {
3366 		BVariant valueData;
3367 		value->PrimitiveValue()->ToVariant(valueData);
3368 
3369 		// usually, the evaluation can give us back an error message to
3370 		// specifically indicate why it failed. If it did, simply use
3371 		// the message directly, otherwise fall back to generating an error
3372 		// message based on the error code
3373 		if (valueData.Type() == B_STRING_TYPE)
3374 			errorMessage = valueData.ToString();
3375 		else {
3376 			errorMessage.SetToFormat("Failed to evaluate expression \"%s\":"
3377 				" %s (%" B_PRId32 ")",
3378 				fPendingTypecastInfo->Expression().String(), strerror(result),
3379 				result);
3380 		}
3381 
3382 	} else if (value->Kind() != EXPRESSION_RESULT_KIND_TYPE) {
3383 		errorMessage.SetToFormat("Expression \"%s\" does not evaluate to a"
3384 			" type.", fPendingTypecastInfo->Expression().String());
3385 	}
3386 
3387 	if (!errorMessage.IsEmpty()) {
3388 		BAlert* alert = new(std::nothrow) BAlert("Typecast error",
3389 			errorMessage, "Close");
3390 		if (alert != NULL)
3391 			alert->Go();
3392 
3393 		return;
3394 	}
3395 
3396 	Type* type = value->GetType();
3397 	BReference<Type> typeRef(type);
3398 	ValueNode* valueNode = NULL;
3399 	ModelNode* node = fPendingTypecastInfo->TargetNode();
3400 	if (TypeHandlerRoster::Default()->CreateValueNode(node->NodeChild(), type,
3401 			NULL, valueNode) != B_OK) {
3402 		return;
3403 	}
3404 
3405 	node->NodeChild()->SetNode(valueNode);
3406 	node->SetCastedType(type);
3407 	fVariableTableModel->NotifyNodeChanged(node);
3408 }
3409 
3410 
3411 void
3412 VariablesView::_HandleEditVariableRequest(ModelNode* node, Value* value)
3413 {
3414 	// get a value handler
3415 	ValueHandler* valueHandler;
3416 	status_t error = ValueHandlerRoster::Default()->FindValueHandler(value,
3417 		valueHandler);
3418 	if (error != B_OK)
3419 		return;
3420 
3421 	ValueNode* valueNode = node->NodeChild()->Node();
3422 
3423 	BReference<ValueHandler> handlerReference(valueHandler, true);
3424 	TableCellValueRenderer* renderer = node->TableCellRenderer();
3425 	TableCellValueEditor* editor = NULL;
3426 	error = valueHandler->GetTableCellValueEditor(value,
3427 		renderer != NULL ? renderer->GetSettings() : NULL, editor);
3428 	if (error != B_OK || editor == NULL)
3429 		return;
3430 
3431 	BReference<TableCellValueEditor> editorReference(editor, true);
3432 
3433 	try {
3434 		fEditWindow = VariableEditWindow::Create(value, valueNode, editor,
3435 			this);
3436 	} catch (...) {
3437 		fEditWindow = NULL;
3438 		return;
3439 	}
3440 
3441 	fEditWindow->Show();
3442 }
3443 
3444 
3445 status_t
3446 VariablesView::_GetTypeForTypeCode(int32 type, Type*& _resultType) const
3447 {
3448 	if (BVariant::TypeIsNumber(type) || type == B_STRING_TYPE) {
3449 		_resultType = new(std::nothrow) SyntheticPrimitiveType(type);
3450 		if (_resultType == NULL)
3451 			return B_NO_MEMORY;
3452 
3453 		return B_OK;
3454 	}
3455 
3456 	return B_NOT_SUPPORTED;
3457 }
3458 
3459 
3460 // #pragma mark - Listener
3461 
3462 
3463 VariablesView::Listener::~Listener()
3464 {
3465 }
3466