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