xref: /haiku/src/apps/debugger/user_interface/gui/team_window/VariablesView.cpp (revision aed35104852941f0f6f3d1dcc5338b5f337d0a3c)
1 /*
2  * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Copyright 2011-2012, Rene Gollent, rene@gollent.com.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 
8 #include "VariablesView.h"
9 
10 #include <stdio.h>
11 
12 #include <new>
13 
14 #include <Looper.h>
15 #include <PopUpMenu.h>
16 #include <ToolTip.h>
17 
18 #include <AutoDeleter.h>
19 #include <AutoLocker.h>
20 
21 #include "table/TableColumns.h"
22 
23 #include "ActionMenuItem.h"
24 #include "Architecture.h"
25 #include "FunctionID.h"
26 #include "FunctionInstance.h"
27 #include "GuiSettingsUtils.h"
28 #include "MessageCodes.h"
29 #include "Register.h"
30 #include "SettingsMenu.h"
31 #include "StackFrame.h"
32 #include "StackFrameValues.h"
33 #include "TableCellValueRenderer.h"
34 #include "Team.h"
35 #include "Thread.h"
36 #include "Tracing.h"
37 #include "TypeComponentPath.h"
38 #include "TypeHandlerRoster.h"
39 #include "Value.h"
40 #include "ValueHandler.h"
41 #include "ValueHandlerRoster.h"
42 #include "ValueLocation.h"
43 #include "ValueNode.h"
44 #include "ValueNodeContainer.h"
45 #include "Variable.h"
46 #include "VariableValueNodeChild.h"
47 #include "VariablesViewState.h"
48 #include "VariablesViewStateHistory.h"
49 
50 
51 enum {
52 	VALUE_NODE_TYPE	= 'valn'
53 };
54 
55 
56 enum {
57 	MSG_MODEL_NODE_HIDDEN			= 'monh',
58 	MSG_VALUE_NODE_NEEDS_VALUE		= 'mvnv',
59 	MSG_RESTORE_PARTIAL_VIEW_STATE	= 'mpvs'
60 };
61 
62 
63 // maximum number of array elements to show by default
64 static const uint64 kMaxArrayElementCount = 10;
65 
66 
67 class VariablesView::ContainerListener : public ValueNodeContainer::Listener {
68 public:
69 								ContainerListener(BHandler* indirectTarget);
70 
71 			void				SetModel(VariableTableModel* model);
72 
73 	virtual	void				ValueNodeChanged(ValueNodeChild* nodeChild,
74 									ValueNode* oldNode, ValueNode* newNode);
75 	virtual	void				ValueNodeChildrenCreated(ValueNode* node);
76 	virtual	void				ValueNodeChildrenDeleted(ValueNode* node);
77 	virtual	void				ValueNodeValueChanged(ValueNode* node);
78 
79 	virtual void				ModelNodeHidden(ModelNode* node);
80 
81 	virtual void				ModelNodeValueRequested(ModelNode* node);
82 
83 	virtual void				ModelNodeRestoreViewStateRequested(ModelNode* node);
84 
85 private:
86 			BHandler*			fIndirectTarget;
87 			VariableTableModel*	fModel;
88 };
89 
90 
91 class VariablesView::ModelNode : public BReferenceable {
92 public:
93 	ModelNode(ModelNode* parent, Variable* variable, ValueNodeChild* nodeChild,
94 		bool isPresentationNode)
95 		:
96 		fParent(parent),
97 		fNodeChild(nodeChild),
98 		fVariable(variable),
99 		fValue(NULL),
100 		fValueHandler(NULL),
101 		fTableCellRenderer(NULL),
102 		fComponentPath(NULL),
103 		fIsPresentationNode(isPresentationNode),
104 		fHidden(false)
105 	{
106 		fNodeChild->AcquireReference();
107 	}
108 
109 	~ModelNode()
110 	{
111 		SetTableCellRenderer(NULL);
112 		SetValueHandler(NULL);
113 		SetValue(NULL);
114 
115 		for (int32 i = 0; ModelNode* child = fChildren.ItemAt(i); i++)
116 			child->ReleaseReference();
117 
118 		fNodeChild->ReleaseReference();
119 
120 		if (fComponentPath != NULL)
121 			fComponentPath->ReleaseReference();
122 	}
123 
124 	status_t Init()
125 	{
126 		fComponentPath = new(std::nothrow) TypeComponentPath();
127 		if (fComponentPath == NULL)
128 			return B_NO_MEMORY;
129 
130 		if (fParent != NULL)
131 			*fComponentPath = *fParent->GetPath();
132 
133 		TypeComponent component;
134 		// TODO: this should actually discriminate between different
135 		// classes of type component kinds
136 		component.SetToBaseType(fNodeChild->GetType()->Kind(),
137 			0, fNodeChild->Name());
138 
139 		fComponentPath->AddComponent(component);
140 
141 		return B_OK;
142 	}
143 
144 	ModelNode* Parent() const
145 	{
146 		return fParent;
147 	}
148 
149 	ValueNodeChild* NodeChild() const
150 	{
151 		return fNodeChild;
152 	}
153 
154 	const BString& Name() const
155 	{
156 		return fNodeChild->Name();
157 	}
158 
159 	Type* GetType() const
160 	{
161 		return fNodeChild->GetType();
162 	}
163 
164 	Variable* GetVariable() const
165 	{
166 		return fVariable;
167 	}
168 
169 	Value* GetValue() const
170 	{
171 		return fValue;
172 	}
173 
174 	void SetValue(Value* value)
175 	{
176 		if (value == fValue)
177 			return;
178 
179 		if (fValue != NULL)
180 			fValue->ReleaseReference();
181 
182 		fValue = value;
183 
184 		if (fValue != NULL)
185 			fValue->AcquireReference();
186 	}
187 
188 	TypeComponentPath* GetPath() const
189 	{
190 		return fComponentPath;
191 	}
192 
193 	ValueHandler* GetValueHandler() const
194 	{
195 		return fValueHandler;
196 	}
197 
198 	void SetValueHandler(ValueHandler* handler)
199 	{
200 		if (handler == fValueHandler)
201 			return;
202 
203 		if (fValueHandler != NULL)
204 			fValueHandler->ReleaseReference();
205 
206 		fValueHandler = handler;
207 
208 		if (fValueHandler != NULL)
209 			fValueHandler->AcquireReference();
210 	}
211 
212 
213 	TableCellValueRenderer* TableCellRenderer() const
214 	{
215 		return fTableCellRenderer;
216 	}
217 
218 	void SetTableCellRenderer(TableCellValueRenderer* renderer)
219 	{
220 		if (renderer == fTableCellRenderer)
221 			return;
222 
223 		if (fTableCellRenderer != NULL)
224 			fTableCellRenderer->ReleaseReference();
225 
226 		fTableCellRenderer = renderer;
227 
228 		if (fTableCellRenderer != NULL)
229 			fTableCellRenderer->AcquireReference();
230 	}
231 
232 	bool IsPresentationNode() const
233 	{
234 		return fIsPresentationNode;
235 	}
236 
237 	bool IsHidden() const
238 	{
239 		return fHidden;
240 	}
241 
242 	void SetHidden(bool hidden)
243 	{
244 		fHidden = hidden;
245 	}
246 
247 	int32 CountChildren() const
248 	{
249 		return fChildren.CountItems();
250 	}
251 
252 	ModelNode* ChildAt(int32 index) const
253 	{
254 		return fChildren.ItemAt(index);
255 	}
256 
257 	int32 IndexOf(ModelNode* child) const
258 	{
259 		return fChildren.IndexOf(child);
260 	}
261 
262 	bool AddChild(ModelNode* child)
263 	{
264 		if (!fChildren.AddItem(child))
265 			return false;
266 
267 		child->AcquireReference();
268 		return true;
269 	}
270 
271 private:
272 	typedef BObjectList<ModelNode> ChildList;
273 
274 private:
275 	ModelNode*				fParent;
276 	ValueNodeChild*			fNodeChild;
277 	Variable*				fVariable;
278 	Value*					fValue;
279 	ValueHandler*			fValueHandler;
280 	TableCellValueRenderer*	fTableCellRenderer;
281 	ChildList				fChildren;
282 	TypeComponentPath*		fComponentPath;
283 	bool					fIsPresentationNode;
284 	bool					fHidden;
285 
286 public:
287 	ModelNode*			fNext;
288 };
289 
290 
291 // #pragma mark - VariableValueColumn
292 
293 
294 class VariablesView::VariableValueColumn : public StringTableColumn {
295 public:
296 	VariableValueColumn(int32 modelIndex, const char* title, float width,
297 		float minWidth, float maxWidth, uint32 truncate = B_TRUNCATE_MIDDLE,
298 		alignment align = B_ALIGN_RIGHT)
299 		:
300 		StringTableColumn(modelIndex, title, width, minWidth, maxWidth,
301 			truncate, align)
302 	{
303 	}
304 
305 protected:
306 	void DrawValue(const BVariant& value, BRect rect, BView* targetView)
307 	{
308 		// draw the node's value with the designated renderer
309 		if (value.Type() == VALUE_NODE_TYPE) {
310 			ModelNode* node = dynamic_cast<ModelNode*>(value.ToReferenceable());
311 			if (node != NULL && node->GetValue() != NULL
312 				&& node->TableCellRenderer() != NULL) {
313 				node->TableCellRenderer()->RenderValue(node->GetValue(), rect,
314 					targetView);
315 				return;
316 			}
317 		} else if (value.Type() == B_STRING_TYPE) {
318 			fField.SetString(value.ToString());
319 		} else {
320 			// fall back to drawing an empty string
321 			fField.SetString("");
322 		}
323 		fField.SetWidth(Width());
324 		fColumn.DrawField(&fField, rect, targetView);
325 	}
326 
327 	float GetPreferredWidth(const BVariant& value, BView* targetView) const
328 	{
329 		// get the preferred width from the node's designated renderer
330 		if (value.Type() == VALUE_NODE_TYPE) {
331 			ModelNode* node = dynamic_cast<ModelNode*>(value.ToReferenceable());
332 			if (node != NULL && node->GetValue() != NULL
333 				&& node->TableCellRenderer() != NULL) {
334 				return node->TableCellRenderer()->PreferredValueWidth(
335 					node->GetValue(), targetView);
336 			}
337 		}
338 
339 		return fColumn.BTitledColumn::GetPreferredWidth(NULL, targetView);
340 	}
341 
342 	virtual BField* PrepareField(const BVariant& _value) const
343 	{
344 		return NULL;
345 	}
346 };
347 
348 
349 // #pragma mark - VariableTableModel
350 
351 
352 class VariablesView::VariableTableModel : public TreeTableModel,
353 	public TreeTableToolTipProvider {
354 public:
355 								VariableTableModel();
356 								~VariableTableModel();
357 
358 			status_t			Init();
359 
360 			void				SetContainerListener(
361 									ContainerListener* listener);
362 
363 			void				SetStackFrame(Thread* thread,
364 									StackFrame* stackFrame);
365 
366 			void				ValueNodeChanged(ValueNodeChild* nodeChild,
367 									ValueNode* oldNode, ValueNode* newNode);
368 			void				ValueNodeChildrenCreated(ValueNode* node);
369 			void				ValueNodeChildrenDeleted(ValueNode* node);
370 			void				ValueNodeValueChanged(ValueNode* node);
371 
372 	virtual	int32				CountColumns() const;
373 	virtual	void*				Root() const;
374 	virtual	int32				CountChildren(void* parent) const;
375 	virtual	void*				ChildAt(void* parent, int32 index) const;
376 	virtual	bool				GetValueAt(void* object, int32 columnIndex,
377 									BVariant& _value);
378 
379 			bool				GetTreePath(ModelNode* node,
380 									TreeTablePath& _path) const;
381 
382 			void				NodeExpanded(ModelNode* node);
383 
384 			void				NotifyNodeChanged(ModelNode* node);
385 			void				NotifyNodeHidden(ModelNode* node);
386 
387 	virtual	bool				GetToolTipForTablePath(
388 									const TreeTablePath& path,
389 									int32 columnIndex, BToolTip** _tip);
390 
391 private:
392 			struct NodeHashDefinition {
393 				typedef ValueNodeChild*	KeyType;
394 				typedef	ModelNode		ValueType;
395 
396 				size_t HashKey(const ValueNodeChild* key) const
397 				{
398 					return (size_t)key;
399 				}
400 
401 				size_t Hash(const ModelNode* value) const
402 				{
403 					return HashKey(value->NodeChild());
404 				}
405 
406 				bool Compare(const ValueNodeChild* key,
407 					const ModelNode* value) const
408 				{
409 					return value->NodeChild() == key;
410 				}
411 
412 				ModelNode*& GetLink(ModelNode* value) const
413 				{
414 					return value->fNext;
415 				}
416 			};
417 
418 			typedef BObjectList<ModelNode> NodeList;
419 			typedef BOpenHashTable<NodeHashDefinition> NodeTable;
420 
421 private:
422 			// container must be locked
423 
424 			status_t			_AddNode(Variable* variable, ModelNode* parent,
425 									ValueNodeChild* nodeChild,
426 									bool isPresentationNode = false,
427 									bool isOnlyChild = false);
428 			void				_AddNode(Variable* variable);
429 			status_t			_CreateValueNode(ValueNodeChild* nodeChild);
430 			status_t			_AddChildNodes(ValueNodeChild* nodeChild);
431 
432 //			ModelNode*			_GetNode(Variable* variable,
433 //									TypeComponentPath* path) const;
434 
435 private:
436 			Thread*				fThread;
437 			StackFrame*			fStackFrame;
438 			ValueNodeContainer*	fContainer;
439 			ContainerListener*	fContainerListener;
440 			NodeList			fNodes;
441 			NodeTable			fNodeTable;
442 };
443 
444 
445 class VariablesView::ContextMenu : public BPopUpMenu {
446 public:
447 	ContextMenu(const BMessenger& parent, const char* name)
448 		: BPopUpMenu(name, false, false),
449 		  fParent(parent)
450 	{
451 	}
452 
453 	virtual void Hide()
454 	{
455 		BPopUpMenu::Hide();
456 
457 		BMessage message(MSG_VARIABLES_VIEW_CONTEXT_MENU_DONE);
458 		message.AddPointer("menu", this);
459 		fParent.SendMessage(&message);
460 	}
461 
462 private:
463 	BMessenger	fParent;
464 };
465 
466 
467 // #pragma mark - TableCellContextMenuTracker
468 
469 
470 class VariablesView::TableCellContextMenuTracker : public BReferenceable,
471 	Settings::Listener {
472 public:
473 	TableCellContextMenuTracker(ModelNode* node, BLooper* parentLooper,
474 		const BMessenger& parent)
475 		:
476 		fNode(node),
477 		fParentLooper(parentLooper),
478 		fParent(parent),
479 		fRendererSettings(NULL),
480 		fRendererSettingsMenu(NULL),
481 		fRendererMenuAdded(false),
482 		fMenuPreparedToShow(false)
483 	{
484 		fNode->AcquireReference();
485 	}
486 
487 	~TableCellContextMenuTracker()
488 	{
489 		FinishMenu(true);
490 
491 		if (fRendererSettingsMenu != NULL)
492 			fRendererSettingsMenu->ReleaseReference();
493 
494 		if (fRendererSettings != NULL)
495 			fRendererSettings->ReleaseReference();
496 
497 		fNode->ReleaseReference();
498 	}
499 
500 	status_t Init(Settings* rendererSettings,
501 		SettingsMenu* rendererSettingsMenu,
502 		ContextActionList* preSettingsActions = NULL,
503 		ContextActionList* postSettingsActions = NULL)
504 	{
505 		if (rendererSettings == NULL && preSettingsActions == NULL
506 			&& postSettingsActions == NULL) {
507 			return B_BAD_VALUE;
508 		}
509 
510 		if (rendererSettings != NULL) {
511 			fRendererSettings = rendererSettings;
512 			fRendererSettings->AcquireReference();
513 
514 
515 			fRendererSettingsMenu = rendererSettingsMenu;
516 			fRendererSettingsMenu->AcquireReference();
517 		}
518 
519 		fContextMenu = new(std::nothrow) ContextMenu(fParent,
520 			"table cell settings popup");
521 		if (fContextMenu == NULL)
522 			return B_NO_MEMORY;
523 
524 		status_t error = B_OK;
525 		if (preSettingsActions != NULL
526 			&& preSettingsActions->CountItems() > 0) {
527 			error = _AddActionItems(preSettingsActions);
528 			if (error != B_OK)
529 				return error;
530 
531 			if (fRendererSettingsMenu != NULL || postSettingsActions != NULL)
532 				fContextMenu->AddSeparatorItem();
533 		}
534 
535 		if (fRendererSettingsMenu != NULL) {
536 			error = fRendererSettingsMenu->AddToMenu(fContextMenu,
537 				fContextMenu->CountItems());
538 			if (error != B_OK)
539 				return error;
540 
541 			if (postSettingsActions != NULL)
542 				fContextMenu->AddSeparatorItem();
543 		}
544 
545 		if (postSettingsActions != NULL) {
546 			error = _AddActionItems(postSettingsActions);
547 			if (error != B_OK)
548 				return error;
549 
550 		}
551 
552 		if (fRendererSettings != NULL) {
553 			AutoLocker<Settings> settingsLocker(fRendererSettings);
554 			fRendererSettings->AddListener(this);
555 			fRendererMenuAdded = true;
556 		}
557 
558 		return B_OK;
559 	}
560 
561 	void ShowMenu(BPoint screenWhere)
562 	{
563 		if (fRendererMenuAdded)
564 			fRendererSettingsMenu->PrepareToShow(fParentLooper);
565 
566 		for (int32 i = 0; i < fContextMenu->CountItems(); i++) {
567 			ActionMenuItem* item = dynamic_cast<ActionMenuItem*>(
568 				fContextMenu->ItemAt(i));
569 			if (item != NULL)
570 				item->PrepareToShow(fParentLooper, fParent.Target(NULL));
571 		}
572 
573 		fMenuPreparedToShow = true;
574 
575 		BRect mouseRect(screenWhere, screenWhere);
576 		mouseRect.InsetBy(-4.0, -4.0);
577 		fContextMenu->Go(screenWhere, true, false, mouseRect, true);
578 	}
579 
580 	bool FinishMenu(bool force)
581 	{
582 		bool stillActive = false;
583 
584 		if (fMenuPreparedToShow) {
585 			if (fRendererMenuAdded)
586 				stillActive = fRendererSettingsMenu->Finish(fParentLooper,
587 					force);
588 			for (int32 i = 0; i < fContextMenu->CountItems(); i++) {
589 				ActionMenuItem* item = dynamic_cast<ActionMenuItem*>(
590 					fContextMenu->ItemAt(i));
591 				if (item != NULL) {
592 					stillActive |= item->Finish(fParentLooper,
593 						fParent.Target(NULL), force);
594 				}
595 			}
596 
597 			fMenuPreparedToShow = stillActive;
598 		}
599 
600 		if (fRendererMenuAdded) {
601 			fRendererSettingsMenu->RemoveFromMenu();
602 			fRendererSettings->RemoveListener(this);
603 			fRendererMenuAdded = false;
604 		}
605 
606 		if (fContextMenu != NULL) {
607 			delete fContextMenu;
608 			fContextMenu = NULL;
609 		}
610 
611 		return stillActive;
612 	}
613 
614 private:
615 	// Settings::Listener
616 
617 	virtual void SettingValueChanged(Setting* setting)
618 	{
619 		BMessage message(MSG_VARIABLES_VIEW_NODE_SETTINGS_CHANGED);
620 		fNode->AcquireReference();
621 		if (message.AddPointer("node", fNode) != B_OK
622 			|| fParent.SendMessage(&message) != B_OK) {
623 			fNode->ReleaseReference();
624 		}
625 	}
626 
627 	status_t _AddActionItems(ContextActionList* actions)
628 	{
629 		if (fContextMenu == NULL)
630 			return B_BAD_VALUE;
631 
632 		int32 index = fContextMenu->CountItems();
633 		for (int32 i = 0; ActionMenuItem* item = actions->ItemAt(i); i++) {
634 			if (!fContextMenu->AddItem(item, index + i)) {
635 				for (i--; i >= 0; i--)
636 					fContextMenu->RemoveItem(fContextMenu->ItemAt(index + i));
637 
638 				return B_NO_MEMORY;
639 			}
640 		}
641 
642 		return B_OK;
643 	}
644 
645 private:
646 	ModelNode*		fNode;
647 	BLooper*		fParentLooper;
648 	BMessenger		fParent;
649 	ContextMenu*	fContextMenu;
650 	Settings*		fRendererSettings;
651 	SettingsMenu*	fRendererSettingsMenu;
652 	bool			fRendererMenuAdded;
653 	bool			fMenuPreparedToShow;
654 };
655 
656 
657 // #pragma mark - ContainerListener
658 
659 
660 VariablesView::ContainerListener::ContainerListener(BHandler* indirectTarget)
661 	:
662 	fIndirectTarget(indirectTarget),
663 	fModel(NULL)
664 {
665 }
666 
667 
668 void
669 VariablesView::ContainerListener::SetModel(VariableTableModel* model)
670 {
671 	fModel = model;
672 }
673 
674 
675 void
676 VariablesView::ContainerListener::ValueNodeChanged(ValueNodeChild* nodeChild,
677 	ValueNode* oldNode, ValueNode* newNode)
678 {
679 	// If the looper is already locked, invoke the model's hook synchronously.
680 	if (fIndirectTarget->Looper()->IsLocked()) {
681 		fModel->ValueNodeChanged(nodeChild, oldNode, newNode);
682 		return;
683 	}
684 
685 	// looper not locked yet -- call asynchronously to avoid reverse locking
686 	// order
687 	BReference<ValueNodeChild> nodeChildReference(nodeChild);
688 	BReference<ValueNode> oldNodeReference(oldNode);
689 	BReference<ValueNode> newNodeReference(newNode);
690 
691 	BMessage message(MSG_VALUE_NODE_CHANGED);
692 	if (message.AddPointer("nodeChild", nodeChild) == B_OK
693 		&& message.AddPointer("oldNode", oldNode) == B_OK
694 		&& message.AddPointer("newNode", newNode) == B_OK
695 		&& fIndirectTarget->Looper()->PostMessage(&message, fIndirectTarget)
696 			== B_OK) {
697 		nodeChildReference.Detach();
698 		oldNodeReference.Detach();
699 		newNodeReference.Detach();
700 	}
701 }
702 
703 
704 void
705 VariablesView::ContainerListener::ValueNodeChildrenCreated(ValueNode* node)
706 {
707 	// If the looper is already locked, invoke the model's hook synchronously.
708 	if (fIndirectTarget->Looper()->IsLocked()) {
709 		fModel->ValueNodeChildrenCreated(node);
710 		return;
711 	}
712 
713 	// looper not locked yet -- call asynchronously to avoid reverse locking
714 	// order
715 	BReference<ValueNode> nodeReference(node);
716 
717 	BMessage message(MSG_VALUE_NODE_CHILDREN_CREATED);
718 	if (message.AddPointer("node", node) == B_OK
719 		&& fIndirectTarget->Looper()->PostMessage(&message, fIndirectTarget)
720 			== B_OK) {
721 		nodeReference.Detach();
722 	}
723 }
724 
725 
726 void
727 VariablesView::ContainerListener::ValueNodeChildrenDeleted(ValueNode* node)
728 {
729 	// If the looper is already locked, invoke the model's hook synchronously.
730 	if (fIndirectTarget->Looper()->IsLocked()) {
731 		fModel->ValueNodeChildrenDeleted(node);
732 		return;
733 	}
734 
735 	// looper not locked yet -- call asynchronously to avoid reverse locking
736 	// order
737 	BReference<ValueNode> nodeReference(node);
738 
739 	BMessage message(MSG_VALUE_NODE_CHILDREN_DELETED);
740 	if (message.AddPointer("node", node) == B_OK
741 		&& fIndirectTarget->Looper()->PostMessage(&message, fIndirectTarget)
742 			== B_OK) {
743 		nodeReference.Detach();
744 	}
745 }
746 
747 
748 void
749 VariablesView::ContainerListener::ValueNodeValueChanged(ValueNode* node)
750 {
751 	// If the looper is already locked, invoke the model's hook synchronously.
752 	if (fIndirectTarget->Looper()->IsLocked()) {
753 		fModel->ValueNodeValueChanged(node);
754 		return;
755 	}
756 
757 	// looper not locked yet -- call asynchronously to avoid reverse locking
758 	// order
759 	BReference<ValueNode> nodeReference(node);
760 
761 	BMessage message(MSG_VALUE_NODE_VALUE_CHANGED);
762 	if (message.AddPointer("node", node) == B_OK
763 		&& fIndirectTarget->Looper()->PostMessage(&message, fIndirectTarget)
764 			== B_OK) {
765 		nodeReference.Detach();
766 	}
767 }
768 
769 
770 void
771 VariablesView::ContainerListener::ModelNodeHidden(ModelNode* node)
772 {
773 	BReference<ModelNode> nodeReference(node);
774 
775 	BMessage message(MSG_MODEL_NODE_HIDDEN);
776 	if (message.AddPointer("node", node) == B_OK
777 		&& fIndirectTarget->Looper()->PostMessage(&message, fIndirectTarget)
778 			== B_OK) {
779 		nodeReference.Detach();
780 	}
781 }
782 
783 
784 void
785 VariablesView::ContainerListener::ModelNodeValueRequested(ModelNode* node)
786 {
787 	BReference<ModelNode> nodeReference(node);
788 
789 	BMessage message(MSG_VALUE_NODE_NEEDS_VALUE);
790 	if (message.AddPointer("node", node) == B_OK
791 		&& fIndirectTarget->Looper()->PostMessage(&message, fIndirectTarget)
792 			== B_OK) {
793 		nodeReference.Detach();
794 	}
795 }
796 
797 
798 void
799 VariablesView::ContainerListener::ModelNodeRestoreViewStateRequested(
800 	ModelNode* node)
801 {
802 	BReference<ModelNode> nodeReference(node);
803 
804 	BMessage message(MSG_RESTORE_PARTIAL_VIEW_STATE);
805 	if (message.AddPointer("node", node) == B_OK
806 		&& fIndirectTarget->Looper()->PostMessage(&message, fIndirectTarget)
807 			== B_OK) {
808 		nodeReference.Detach();
809 	}
810 }
811 
812 
813 // #pragma mark - VariableTableModel
814 
815 
816 VariablesView::VariableTableModel::VariableTableModel()
817 	:
818 	fStackFrame(NULL),
819 	fContainer(NULL),
820 	fContainerListener(NULL),
821 	fNodeTable()
822 {
823 }
824 
825 
826 VariablesView::VariableTableModel::~VariableTableModel()
827 {
828 	SetStackFrame(NULL, NULL);
829 }
830 
831 
832 status_t
833 VariablesView::VariableTableModel::Init()
834 {
835 	return fNodeTable.Init();
836 }
837 
838 
839 void
840 VariablesView::VariableTableModel::SetContainerListener(
841 	ContainerListener* listener)
842 {
843 	if (listener == fContainerListener)
844 		return;
845 
846 	if (fContainerListener != NULL) {
847 		if (fContainer != NULL) {
848 			AutoLocker<ValueNodeContainer> containerLocker(fContainer);
849 			fContainer->RemoveListener(fContainerListener);
850 		}
851 
852 		fContainerListener->SetModel(NULL);
853 	}
854 
855 	fContainerListener = listener;
856 
857 	if (fContainerListener != NULL) {
858 		fContainerListener->SetModel(this);
859 
860 		if (fContainer != NULL) {
861 			AutoLocker<ValueNodeContainer> containerLocker(fContainer);
862 			fContainer->AddListener(fContainerListener);
863 		}
864 	}
865 }
866 
867 
868 void
869 VariablesView::VariableTableModel::SetStackFrame(Thread* thread,
870 	StackFrame* stackFrame)
871 {
872 	if (fContainer != NULL) {
873 		AutoLocker<ValueNodeContainer> containerLocker(fContainer);
874 
875 		if (fContainerListener != NULL)
876 			fContainer->RemoveListener(fContainerListener);
877 
878 		fContainer->RemoveAllChildren();
879 		containerLocker.Unlock();
880 		fContainer->ReleaseReference();
881 		fContainer = NULL;
882 	}
883 
884 	fNodeTable.Clear(true);
885 
886 	if (!fNodes.IsEmpty()) {
887 		int32 count = fNodes.CountItems();
888 		for (int32 i = 0; i < count; i++)
889 			fNodes.ItemAt(i)->ReleaseReference();
890 		fNodes.MakeEmpty();
891 		NotifyNodesRemoved(TreeTablePath(), 0, count);
892 	}
893 
894 	fStackFrame = stackFrame;
895 	fThread = thread;
896 
897 	if (fStackFrame != NULL) {
898 		fContainer = new(std::nothrow) ValueNodeContainer;
899 		if (fContainer == NULL)
900 			return;
901 
902 		status_t error = fContainer->Init();
903 		if (error != B_OK) {
904 			delete fContainer;
905 			fContainer = NULL;
906 			return;
907 		}
908 
909 		AutoLocker<ValueNodeContainer> containerLocker(fContainer);
910 
911 		if (fContainerListener != NULL)
912 			fContainer->AddListener(fContainerListener);
913 
914 		for (int32 i = 0; Variable* variable = fStackFrame->ParameterAt(i);
915 				i++) {
916 			_AddNode(variable);
917 		}
918 
919 		for (int32 i = 0; Variable* variable
920 				= fStackFrame->LocalVariableAt(i); i++) {
921 			_AddNode(variable);
922 		}
923 
924 //		if (!fNodes.IsEmpty())
925 //			NotifyNodesAdded(TreeTablePath(), 0, fNodes.CountItems());
926 	}
927 }
928 
929 
930 void
931 VariablesView::VariableTableModel::ValueNodeChanged(ValueNodeChild* nodeChild,
932 	ValueNode* oldNode, ValueNode* newNode)
933 {
934 	if (fContainer == NULL)
935 		return;
936 
937 	AutoLocker<ValueNodeContainer> containerLocker(fContainer);
938 // TODO:...
939 }
940 
941 
942 void
943 VariablesView::VariableTableModel::ValueNodeChildrenCreated(
944 	ValueNode* valueNode)
945 {
946 	if (fContainer == NULL)
947 		return;
948 
949 	AutoLocker<ValueNodeContainer> containerLocker(fContainer);
950 
951 	// check whether we know the node
952 	ValueNodeChild* nodeChild = valueNode->NodeChild();
953 	if (nodeChild == NULL)
954 		return;
955 
956 	ModelNode* modelNode = fNodeTable.Lookup(nodeChild);
957 	if (modelNode == NULL)
958 		return;
959 
960 	// Iterate through the children and create model nodes for the ones we
961 	// don't know yet.
962 	int32 childCount = valueNode->CountChildren();
963 	for (int32 i = 0; i < childCount; i++) {
964 		ValueNodeChild* child = valueNode->ChildAt(i);
965 		if (fNodeTable.Lookup(child) == NULL) {
966 			_AddNode(modelNode->GetVariable(), modelNode, child,
967 				child->IsInternal(), childCount == 1);
968 		}
969 
970 		if (valueNode->ChildCreationNeedsValue()) {
971 			ModelNode* childNode = fNodeTable.Lookup(child);
972 			if (childNode != NULL)
973 				fContainerListener->ModelNodeValueRequested(childNode);
974 		}
975 	}
976 
977 	if (valueNode->ChildCreationNeedsValue())
978 		fContainerListener->ModelNodeRestoreViewStateRequested(modelNode);
979 }
980 
981 
982 void
983 VariablesView::VariableTableModel::ValueNodeChildrenDeleted(ValueNode* node)
984 {
985 	if (fContainer == NULL)
986 		return;
987 
988 	AutoLocker<ValueNodeContainer> containerLocker(fContainer);
989 // TODO:...
990 }
991 
992 
993 void
994 VariablesView::VariableTableModel::ValueNodeValueChanged(ValueNode* valueNode)
995 {
996 	if (fContainer == NULL)
997 		return;
998 
999 	AutoLocker<ValueNodeContainer> containerLocker(fContainer);
1000 
1001 	// check whether we know the node
1002 	ValueNodeChild* nodeChild = valueNode->NodeChild();
1003 	if (nodeChild == NULL)
1004 		return;
1005 
1006 	ModelNode* modelNode = fNodeTable.Lookup(nodeChild);
1007 	if (modelNode == NULL)
1008 		return;
1009 
1010 	if (valueNode->ChildCreationNeedsValue()
1011 		&& !valueNode->ChildrenCreated()) {
1012 		status_t error = valueNode->CreateChildren();
1013 		if (error != B_OK)
1014 			return;
1015 
1016 		for (int32 i = 0; i < valueNode->CountChildren(); i++) {
1017 			ValueNodeChild* child = valueNode->ChildAt(i);
1018 			_CreateValueNode(child);
1019 			_AddChildNodes(child);
1020 		}
1021 	}
1022 
1023 	// check whether the value actually changed
1024 	Value* value = valueNode->GetValue();
1025 	if (value == modelNode->GetValue())
1026 		return;
1027 
1028 	// get a value handler
1029 	ValueHandler* valueHandler;
1030 	status_t error = ValueHandlerRoster::Default()->FindValueHandler(value,
1031 		valueHandler);
1032 	if (error != B_OK)
1033 		return;
1034 	BReference<ValueHandler> handlerReference(valueHandler, true);
1035 
1036 	// create a table cell renderer for the value
1037 	TableCellValueRenderer* renderer = NULL;
1038 	error = valueHandler->GetTableCellValueRenderer(value, renderer);
1039 	if (error != B_OK)
1040 		return;
1041 
1042 	// set value/handler/renderer
1043 	modelNode->SetValue(value);
1044 	modelNode->SetValueHandler(valueHandler);
1045 	modelNode->SetTableCellRenderer(renderer);
1046 
1047 	// notify table model listeners
1048 	NotifyNodeChanged(modelNode);
1049 }
1050 
1051 
1052 int32
1053 VariablesView::VariableTableModel::CountColumns() const
1054 {
1055 	return 2;
1056 }
1057 
1058 
1059 void*
1060 VariablesView::VariableTableModel::Root() const
1061 {
1062 	return (void*)this;
1063 }
1064 
1065 
1066 int32
1067 VariablesView::VariableTableModel::CountChildren(void* parent) const
1068 {
1069 	if (parent == this)
1070 		return fNodes.CountItems();
1071 
1072 	// If the node only has a hidden child, pretend the node directly has the
1073 	// child's children.
1074 	ModelNode* modelNode = (ModelNode*)parent;
1075 	int32 childCount = modelNode->CountChildren();
1076 	if (childCount == 1) {
1077 		ModelNode* child = modelNode->ChildAt(0);
1078 		if (child->IsHidden())
1079 			return child->CountChildren();
1080 	}
1081 
1082 	return childCount;
1083 }
1084 
1085 
1086 void*
1087 VariablesView::VariableTableModel::ChildAt(void* parent, int32 index) const
1088 {
1089 	if (parent == this)
1090 		return fNodes.ItemAt(index);
1091 
1092 	// If the node only has a hidden child, pretend the node directly has the
1093 	// child's children.
1094 	ModelNode* modelNode = (ModelNode*)parent;
1095 	int32 childCount = modelNode->CountChildren();
1096 	if (childCount == 1) {
1097 		ModelNode* child = modelNode->ChildAt(0);
1098 		if (child->IsHidden())
1099 			return child->ChildAt(index);
1100 	}
1101 
1102 	return modelNode->ChildAt(index);
1103 }
1104 
1105 
1106 bool
1107 VariablesView::VariableTableModel::GetValueAt(void* object, int32 columnIndex,
1108 	BVariant& _value)
1109 {
1110 	ModelNode* node = (ModelNode*)object;
1111 
1112 	switch (columnIndex) {
1113 		case 0:
1114 			_value.SetTo(node->Name(), B_VARIANT_DONT_COPY_DATA);
1115 			return true;
1116 		case 1:
1117 			if (node->GetValue() == NULL) {
1118 				ValueLocation* location = node->NodeChild()->Location();
1119 				if (location == NULL)
1120 					return false;
1121 
1122 				Type* nodeChildRawType = node->NodeChild()->Node()->GetType()
1123 					->ResolveRawType(false);
1124 				if (nodeChildRawType->Kind() == TYPE_COMPOUND)
1125 				{
1126 					if (location->CountPieces() > 1)
1127 						return false;
1128 
1129 					BString data;
1130 					ValuePieceLocation piece = location->PieceAt(0);
1131 					if (piece.type != VALUE_PIECE_LOCATION_MEMORY)
1132 						return false;
1133 
1134 					data.SetToFormat("[@ 0x%llx]", piece.address);
1135 					_value.SetTo(data);
1136 					return true;
1137 				}
1138 				return false;
1139 			}
1140 
1141 			_value.SetTo(node, VALUE_NODE_TYPE);
1142 			return true;
1143 		default:
1144 			return false;
1145 	}
1146 }
1147 
1148 
1149 void
1150 VariablesView::VariableTableModel::NodeExpanded(ModelNode* node)
1151 {
1152 	if (fContainer == NULL)
1153 		return;
1154 
1155 	AutoLocker<ValueNodeContainer> containerLocker(fContainer);
1156 
1157 	// add children of all children
1158 
1159 	// If the node only has a hidden child, add the child's children instead.
1160 	if (node->CountChildren() == 1) {
1161 		ModelNode* child = node->ChildAt(0);
1162 		if (child->IsHidden())
1163 			node = child;
1164 	}
1165 
1166 	// add the children
1167 	for (int32 i = 0; ModelNode* child = node->ChildAt(i); i++)
1168 		_AddChildNodes(child->NodeChild());
1169 }
1170 
1171 
1172 void
1173 VariablesView::VariableTableModel::NotifyNodeChanged(ModelNode* node)
1174 {
1175 	if (!node->IsHidden()) {
1176 		TreeTablePath treePath;
1177 		if (GetTreePath(node, treePath)) {
1178 			int32 index = treePath.RemoveLastComponent();
1179 			NotifyNodesChanged(treePath, index, 1);
1180 		}
1181 	}
1182 }
1183 
1184 
1185 void
1186 VariablesView::VariableTableModel::NotifyNodeHidden(ModelNode* node)
1187 {
1188 	fContainerListener->ModelNodeHidden(node);
1189 }
1190 
1191 
1192 bool
1193 VariablesView::VariableTableModel::GetToolTipForTablePath(
1194 	const TreeTablePath& path, int32 columnIndex, BToolTip** _tip)
1195 {
1196 	ModelNode* node = (ModelNode*)NodeForPath(path);
1197 	if (node == NULL)
1198 		return false;
1199 
1200 	if (node->NodeChild()->LocationResolutionState() != B_OK)
1201 		return false;
1202 
1203 	ValueLocation* location = node->NodeChild()->Location();
1204 	BString tipData;
1205 	for (int32 i = 0; i < location->CountPieces(); i++) {
1206 		ValuePieceLocation piece = location->PieceAt(i);
1207 		BString pieceData;
1208 		switch (piece.type) {
1209 			case VALUE_PIECE_LOCATION_MEMORY:
1210 				pieceData.SetToFormat("(%ld): Address: 0x%llx, Size: "
1211 					"%lld bytes", i, piece.address, piece.size);
1212 				break;
1213 			case VALUE_PIECE_LOCATION_REGISTER:
1214 			{
1215 				Architecture* architecture = fThread->GetTeam()->GetArchitecture();
1216 				pieceData.SetToFormat("(%ld): Register (%s)",
1217 					i, architecture->Registers()[piece.reg].Name());
1218 
1219 				break;
1220 			}
1221 			default:
1222 				break;
1223 		}
1224 
1225 		tipData	+= pieceData;
1226 		if (i < location->CountPieces() - 1)
1227 			tipData += "\n";
1228 	}
1229 
1230 	if (tipData.IsEmpty())
1231 		return false;
1232 
1233 	*_tip = new(std::nothrow) BTextToolTip(tipData);
1234 	if (*_tip == NULL)
1235 		return false;
1236 
1237 	return true;
1238 }
1239 
1240 
1241 status_t
1242 VariablesView::VariableTableModel::_AddNode(Variable* variable,
1243 	ModelNode* parent, ValueNodeChild* nodeChild, bool isPresentationNode,
1244 	bool isOnlyChild)
1245 {
1246 	// Don't create nodes for unspecified types -- we can't get/show their
1247 	// value anyway.
1248 	Type* nodeChildRawType = nodeChild->GetType()->ResolveRawType(false);
1249 	if (nodeChildRawType->Kind() == TYPE_UNSPECIFIED)
1250 		return B_OK;
1251 
1252 	ModelNode* node = new(std::nothrow) ModelNode(parent, variable, nodeChild,
1253 		isPresentationNode);
1254 	BReference<ModelNode> nodeReference(node, true);
1255 	if (node == NULL || node->Init() != B_OK)
1256 		return B_NO_MEMORY;
1257 
1258 	int32 childIndex;
1259 
1260 	if (parent != NULL) {
1261 		childIndex = parent->CountChildren();
1262 
1263 		if (!parent->AddChild(node))
1264 			return B_NO_MEMORY;
1265 		// the parent has a reference, now
1266 	} else {
1267 		childIndex = fNodes.CountItems();
1268 
1269 		if (!fNodes.AddItem(node))
1270 			return B_NO_MEMORY;
1271 		nodeReference.Detach();
1272 			// the fNodes list has a reference, now
1273 	}
1274 
1275 	fNodeTable.Insert(node);
1276 
1277 	// if an address type node has only a single child, and that child
1278 	// is a compound type, mark it hidden
1279 	if (isOnlyChild && parent != NULL) {
1280 		ValueNode* parentValueNode = parent->NodeChild()->Node();
1281 		if (parentValueNode != NULL
1282 			&& parentValueNode->GetType()->ResolveRawType(false)->Kind()
1283 				== TYPE_ADDRESS
1284 			&& nodeChildRawType->Kind() == TYPE_COMPOUND) {
1285 			node->SetHidden(true);
1286 
1287 			// we need to tell the listener about nodes like this so any
1288 			// necessary actions can be taken for them (i.e. value resolution),
1289 			// since they're otherwise invisible to outsiders.
1290 			NotifyNodeHidden(node);
1291 		}
1292 	}
1293 
1294 	// notify table model listeners
1295 	if (!node->IsHidden()) {
1296 		TreeTablePath path;
1297 		if (parent == NULL || GetTreePath(parent, path))
1298 			NotifyNodesAdded(path, childIndex, 1);
1299 	}
1300 
1301 	// if the node is hidden, add its children
1302 	if (node->IsHidden())
1303 		_AddChildNodes(nodeChild);
1304 
1305 	return B_OK;
1306 }
1307 
1308 
1309 void
1310 VariablesView::VariableTableModel::_AddNode(Variable* variable)
1311 {
1312 	// create the node child for the variable
1313 	ValueNodeChild* nodeChild = new (std::nothrow) VariableValueNodeChild(
1314 		variable);
1315 	BReference<ValueNodeChild> nodeChildReference(nodeChild, true);
1316 	if (nodeChild == NULL || !fContainer->AddChild(nodeChild)) {
1317 		delete nodeChild;
1318 		return;
1319 	}
1320 
1321 	// create the model node
1322 	status_t error = _AddNode(variable, NULL, nodeChild, false);
1323 	if (error != B_OK)
1324 		return;
1325 
1326 	// automatically add child nodes for the top level nodes
1327 	_AddChildNodes(nodeChild);
1328 }
1329 
1330 
1331 status_t
1332 VariablesView::VariableTableModel::_CreateValueNode(ValueNodeChild* nodeChild)
1333 {
1334 	if (nodeChild->Node() != NULL)
1335 		return B_OK;
1336 
1337 	// create the node
1338 	ValueNode* valueNode;
1339 	status_t error;
1340 	if (nodeChild->IsInternal()) {
1341 		error = nodeChild->CreateInternalNode(valueNode);
1342 	} else {
1343 		error = TypeHandlerRoster::Default()->CreateValueNode(nodeChild,
1344 			nodeChild->GetType(), valueNode);
1345 	}
1346 
1347 	if (error != B_OK)
1348 		return error;
1349 
1350 	nodeChild->SetNode(valueNode);
1351 	valueNode->ReleaseReference();
1352 
1353 	return B_OK;
1354 }
1355 
1356 
1357 status_t
1358 VariablesView::VariableTableModel::_AddChildNodes(ValueNodeChild* nodeChild)
1359 {
1360 	// create a value node for the value node child, if doesn't have one yet
1361 	ValueNode* valueNode = nodeChild->Node();
1362 	if (valueNode == NULL) {
1363 		status_t error = _CreateValueNode(nodeChild);
1364 		if (error != B_OK)
1365 			return error;
1366 		valueNode = nodeChild->Node();
1367 	}
1368 
1369 	// check if this node requires child creation
1370 	// to be deferred until after its location/value have been resolved
1371 	if (valueNode->ChildCreationNeedsValue())
1372 		return B_OK;
1373 
1374 	// create the children, if not done yet
1375 	if (valueNode->ChildrenCreated())
1376 		return B_OK;
1377 
1378 	return valueNode->CreateChildren();
1379 }
1380 
1381 
1382 //VariablesView::ModelNode*
1383 //VariablesView::VariableTableModel::_GetNode(Variable* variable,
1384 //	TypeComponentPath* path) const
1385 //{
1386 //	// find the variable node
1387 //	ModelNode* node;
1388 //	for (int32 i = 0; (node = fNodes.ItemAt(i)) != NULL; i++) {
1389 //		if (node->GetVariable() == variable)
1390 //			break;
1391 //	}
1392 //	if (node == NULL)
1393 //		return NULL;
1394 //
1395 //	// Now walk along the path, finding the respective child node for each
1396 //	// component (might be several components at once).
1397 //	int32 componentCount = path->CountComponents();
1398 //	for (int32 i = 0; i < componentCount;) {
1399 //		ModelNode* childNode = NULL;
1400 //
1401 //		for (int32 k = 0; (childNode = node->ChildAt(k)) != NULL; k++) {
1402 //			TypeComponentPath* childPath = childNode->Path();
1403 //			int32 childComponentCount = childPath->CountComponents();
1404 //			if (childComponentCount > componentCount)
1405 //				continue;
1406 //
1407 //			for (int32 componentIndex = i;
1408 //				componentIndex < childComponentCount; componentIndex++) {
1409 //				TypeComponent childComponent
1410 //					= childPath->ComponentAt(componentIndex);
1411 //				TypeComponent pathComponent
1412 //					= path->ComponentAt(componentIndex);
1413 //				if (childComponent != pathComponent) {
1414 //					if (componentIndex + 1 == childComponentCount
1415 //						&& pathComponent.HasPrefix(childComponent)) {
1416 //						// The last child component is a prefix of the
1417 //						// corresponding path component. We consider this a
1418 //						// match, but need to recheck the component with the
1419 //						// next node level.
1420 //						childComponentCount--;
1421 //						break;
1422 //					}
1423 //
1424 //					// mismatch -- skip the child
1425 //					childNode = NULL;
1426 //					break;
1427 //				}
1428 //			}
1429 //
1430 //			if (childNode != NULL) {
1431 //				// got a match -- skip the matched children components
1432 //				i = childComponentCount;
1433 //				break;
1434 //			}
1435 //		}
1436 //
1437 //		if (childNode == NULL)
1438 //			return NULL;
1439 //
1440 //		node = childNode;
1441 //	}
1442 //
1443 //	return node;
1444 //}
1445 
1446 
1447 bool
1448 VariablesView::VariableTableModel::GetTreePath(ModelNode* node,
1449 	TreeTablePath& _path) const
1450 {
1451 	// recurse, if the node has a parent
1452 	if (ModelNode* parent = node->Parent()) {
1453 		if (!GetTreePath(parent, _path))
1454 			return false;
1455 
1456 		if (node->IsHidden())
1457 			return true;
1458 
1459 		return _path.AddComponent(parent->IndexOf(node));
1460 	}
1461 
1462 	// no parent -- get the index and start the path
1463 	int32 index = fNodes.IndexOf(node);
1464 	_path.Clear();
1465 	return index >= 0 && _path.AddComponent(index);
1466 }
1467 
1468 
1469 // #pragma mark - VariablesView
1470 
1471 
1472 VariablesView::VariablesView(Listener* listener)
1473 	:
1474 	BGroupView(B_VERTICAL),
1475 	fThread(NULL),
1476 	fStackFrame(NULL),
1477 	fVariableTable(NULL),
1478 	fVariableTableModel(NULL),
1479 	fContainerListener(NULL),
1480 	fPreviousViewState(NULL),
1481 	fViewStateHistory(NULL),
1482 	fTableCellContextMenuTracker(NULL),
1483 	fListener(listener)
1484 {
1485 	SetName("Variables");
1486 }
1487 
1488 
1489 VariablesView::~VariablesView()
1490 {
1491 	SetStackFrame(NULL, NULL);
1492 	fVariableTable->SetTreeTableModel(NULL);
1493 
1494 	if (fPreviousViewState != NULL)
1495 		fPreviousViewState->ReleaseReference();
1496 	delete fViewStateHistory;
1497 
1498 	if (fVariableTableModel != NULL) {
1499 		fVariableTableModel->SetContainerListener(NULL);
1500 		delete fVariableTableModel;
1501 	}
1502 
1503 	delete fContainerListener;
1504 }
1505 
1506 
1507 /*static*/ VariablesView*
1508 VariablesView::Create(Listener* listener)
1509 {
1510 	VariablesView* self = new VariablesView(listener);
1511 
1512 	try {
1513 		self->_Init();
1514 	} catch (...) {
1515 		delete self;
1516 		throw;
1517 	}
1518 
1519 	return self;
1520 }
1521 
1522 
1523 void
1524 VariablesView::SetStackFrame(Thread* thread, StackFrame* stackFrame)
1525 {
1526 	if (thread == fThread && stackFrame == fStackFrame)
1527 		return;
1528 
1529 	_SaveViewState();
1530 
1531 	_FinishContextMenu(true);
1532 
1533 	if (fThread != NULL)
1534 		fThread->ReleaseReference();
1535 	if (fStackFrame != NULL)
1536 		fStackFrame->ReleaseReference();
1537 
1538 	fThread = thread;
1539 	fStackFrame = stackFrame;
1540 
1541 	if (fThread != NULL)
1542 		fThread->AcquireReference();
1543 	if (fStackFrame != NULL)
1544 		fStackFrame->AcquireReference();
1545 
1546 	fVariableTableModel->SetStackFrame(fThread, fStackFrame);
1547 
1548 	// request loading the parameter and variable values
1549 	if (fThread != NULL && fStackFrame != NULL) {
1550 		AutoLocker<Team> locker(fThread->GetTeam());
1551 
1552 		void* root = fVariableTableModel->Root();
1553 		int32 count = fVariableTableModel->CountChildren(root);
1554 		for (int32 i = 0; i < count; i++) {
1555 			ModelNode* node = (ModelNode*)fVariableTableModel->ChildAt(root, i);
1556 			_RequestNodeValue(node);
1557 		}
1558 	}
1559 
1560 	_RestoreViewState();
1561 }
1562 
1563 
1564 void
1565 VariablesView::MessageReceived(BMessage* message)
1566 {
1567 	switch (message->what) {
1568 		case MSG_SHOW_INSPECTOR_WINDOW:
1569 		{
1570 			// TODO: it'd probably be more ideal to extend the context
1571 			// action mechanism to allow one to specify an explicit
1572 			// target for each action rather than them all defaulting
1573 			// to targetting here.
1574 			Looper()->PostMessage(message);
1575 			break;
1576 		}
1577 		case MSG_VALUE_NODE_CHANGED:
1578 		{
1579 			ValueNodeChild* nodeChild;
1580 			ValueNode* oldNode;
1581 			ValueNode* newNode;
1582 			if (message->FindPointer("nodeChild", (void**)&nodeChild) == B_OK
1583 				&& message->FindPointer("oldNode", (void**)&oldNode) == B_OK
1584 				&& message->FindPointer("newNode", (void**)&newNode) == B_OK) {
1585 				BReference<ValueNodeChild> nodeChildReference(nodeChild, true);
1586 				BReference<ValueNode> oldNodeReference(oldNode, true);
1587 				BReference<ValueNode> newNodeReference(newNode, true);
1588 
1589 				fVariableTableModel->ValueNodeChanged(nodeChild, oldNode,
1590 					newNode);
1591 			}
1592 
1593 			break;
1594 		}
1595 		case MSG_VALUE_NODE_CHILDREN_CREATED:
1596 		{
1597 			ValueNode* node;
1598 			if (message->FindPointer("node", (void**)&node) == B_OK) {
1599 				BReference<ValueNode> newNodeReference(node, true);
1600 				fVariableTableModel->ValueNodeChildrenCreated(node);
1601 			}
1602 
1603 			break;
1604 		}
1605 		case MSG_VALUE_NODE_CHILDREN_DELETED:
1606 		{
1607 			ValueNode* node;
1608 			if (message->FindPointer("node", (void**)&node) == B_OK) {
1609 				BReference<ValueNode> newNodeReference(node, true);
1610 				fVariableTableModel->ValueNodeChildrenDeleted(node);
1611 			}
1612 
1613 			break;
1614 		}
1615 		case MSG_VALUE_NODE_VALUE_CHANGED:
1616 		{
1617 			ValueNode* node;
1618 			if (message->FindPointer("node", (void**)&node) == B_OK) {
1619 				BReference<ValueNode> newNodeReference(node, true);
1620 				fVariableTableModel->ValueNodeValueChanged(node);
1621 			}
1622 
1623 			break;
1624 		}
1625 		case MSG_RESTORE_PARTIAL_VIEW_STATE:
1626 		{
1627 			ModelNode* node;
1628 			if (message->FindPointer("node", (void**)&node) == B_OK) {
1629 				TreeTablePath path;
1630 				if (fVariableTableModel->GetTreePath(node, path)) {
1631 					FunctionID* functionID = fStackFrame->Function()
1632 						->GetFunctionID();
1633 					if (functionID == NULL)
1634 						return;
1635 					BReference<FunctionID> functionIDReference(functionID,
1636 						true);
1637 					VariablesViewState* viewState = fViewStateHistory
1638 						->GetState(fThread->ID(), functionID);
1639 					if (viewState != NULL) {
1640 						_ApplyViewStateDescendentNodeInfos(viewState, node,
1641 							path);
1642 					}
1643 				}
1644 			}
1645 			break;
1646 		}
1647 		case MSG_VALUE_NODE_NEEDS_VALUE:
1648 		case MSG_MODEL_NODE_HIDDEN:
1649 		{
1650 			ModelNode* node;
1651 			if (message->FindPointer("node", (void**)&node) == B_OK)
1652 				_RequestNodeValue(node);
1653 
1654 			break;
1655 		}
1656 		case MSG_VARIABLES_VIEW_CONTEXT_MENU_DONE:
1657 		{
1658 			_FinishContextMenu(false);
1659 			break;
1660 		}
1661 		case MSG_VARIABLES_VIEW_NODE_SETTINGS_CHANGED:
1662 		{
1663 			ModelNode* node;
1664 			if (message->FindPointer("node", (void**)&node) != B_OK)
1665 				break;
1666 			BReference<ModelNode> nodeReference(node, true);
1667 
1668 			fVariableTableModel->NotifyNodeChanged(node);
1669 			break;
1670 		}
1671 		default:
1672 			BGroupView::MessageReceived(message);
1673 			break;
1674 	}
1675 }
1676 
1677 
1678 void
1679 VariablesView::DetachedFromWindow()
1680 {
1681 	_FinishContextMenu(true);
1682 }
1683 
1684 
1685 void
1686 VariablesView::LoadSettings(const BMessage& settings)
1687 {
1688 	BMessage tableSettings;
1689 	if (settings.FindMessage("variableTable", &tableSettings) == B_OK) {
1690 		GuiSettingsUtils::UnarchiveTableSettings(tableSettings,
1691 			fVariableTable);
1692 	}
1693 }
1694 
1695 
1696 status_t
1697 VariablesView::SaveSettings(BMessage& settings)
1698 {
1699 	settings.MakeEmpty();
1700 
1701 	BMessage tableSettings;
1702 	status_t result = GuiSettingsUtils::ArchiveTableSettings(tableSettings,
1703 		fVariableTable);
1704 	if (result == B_OK)
1705 		result = settings.AddMessage("variableTable", &tableSettings);
1706 
1707 	return result;
1708 }
1709 
1710 
1711 
1712 
1713 void
1714 VariablesView::TreeTableNodeExpandedChanged(TreeTable* table,
1715 	const TreeTablePath& path, bool expanded)
1716 {
1717 	if (expanded) {
1718 		ModelNode* node = (ModelNode*)fVariableTableModel->NodeForPath(path);
1719 		if (node == NULL)
1720 			return;
1721 
1722 		fVariableTableModel->NodeExpanded(node);
1723 
1724 		// request the values of all children that don't have any yet
1725 
1726 		// If the node only has a hidden child, directly load the child's
1727 		// children's values.
1728 		if (node->CountChildren() == 1) {
1729 			ModelNode* child = node->ChildAt(0);
1730 			if (child->IsHidden())
1731 				node = child;
1732 		}
1733 
1734 		// request the values
1735 		for (int32 i = 0; ModelNode* child = node->ChildAt(i); i++) {
1736 			if (child->IsPresentationNode())
1737 				continue;
1738 
1739 			_RequestNodeValue(child);
1740 		}
1741 	}
1742 }
1743 
1744 
1745 void
1746 VariablesView::TreeTableCellMouseDown(TreeTable* table,
1747 	const TreeTablePath& path, int32 columnIndex, BPoint screenWhere,
1748 	uint32 buttons)
1749 {
1750 	if ((buttons & B_SECONDARY_MOUSE_BUTTON) == 0)
1751 		return;
1752 
1753 	_FinishContextMenu(true);
1754 
1755 	ModelNode* node = (ModelNode*)fVariableTableModel->NodeForPath(path);
1756 	if (node == NULL)
1757 		return;
1758 
1759 	Settings* settings = NULL;
1760 	SettingsMenu* settingsMenu = NULL;
1761 	BReference<SettingsMenu> settingsMenuReference;
1762 	status_t error = B_OK;
1763 	TableCellValueRenderer* cellRenderer = node->TableCellRenderer();
1764 	if (cellRenderer != NULL) {
1765 		settings = cellRenderer->GetSettings();
1766 		if (settings != NULL) {
1767 			error = node->GetValueHandler()
1768 				->CreateTableCellValueSettingsMenu(node->GetValue(), settings,
1769 					settingsMenu);
1770 			settingsMenuReference.SetTo(settingsMenu, true);
1771 			if (error != B_OK)
1772 				return;
1773 		}
1774 	}
1775 
1776 	TableCellContextMenuTracker* tracker = new(std::nothrow)
1777 		TableCellContextMenuTracker(node, Looper(), this);
1778 	BReference<TableCellContextMenuTracker> trackerReference(tracker);
1779 
1780 	ContextActionList* preActionList = new(std::nothrow) ContextActionList;
1781 	if (preActionList == NULL)
1782 		return;
1783 
1784 	BPrivate::ObjectDeleter<ContextActionList> preActionListDeleter(
1785 		preActionList);
1786 
1787 	error = _GetContextActionsForNode(node, preActionList);
1788 	if (error != B_OK)
1789 		return;
1790 
1791 	if (tracker == NULL || tracker->Init(settings, settingsMenu, preActionList) != B_OK)
1792 		return;
1793 
1794 	fTableCellContextMenuTracker = trackerReference.Detach();
1795 	fTableCellContextMenuTracker->ShowMenu(screenWhere);
1796 }
1797 
1798 
1799 void
1800 VariablesView::_Init()
1801 {
1802 	fVariableTable = new TreeTable("variable list", 0, B_FANCY_BORDER);
1803 	AddChild(fVariableTable->ToView());
1804 	fVariableTable->SetSortingEnabled(false);
1805 
1806 	// columns
1807 	fVariableTable->AddColumn(new StringTableColumn(0, "Variable", 80, 40, 1000,
1808 		B_TRUNCATE_END, B_ALIGN_LEFT));
1809 	fVariableTable->AddColumn(new VariableValueColumn(1, "Value", 80, 40, 1000,
1810 		B_TRUNCATE_END, B_ALIGN_RIGHT));
1811 
1812 	fVariableTableModel = new VariableTableModel;
1813 	if (fVariableTableModel->Init() != B_OK)
1814 		throw std::bad_alloc();
1815 	fVariableTable->SetTreeTableModel(fVariableTableModel);
1816 	fVariableTable->SetToolTipProvider(fVariableTableModel);
1817 
1818 	fContainerListener = new ContainerListener(this);
1819 	fVariableTableModel->SetContainerListener(fContainerListener);
1820 
1821 	fVariableTable->AddTreeTableListener(this);
1822 
1823 	fViewStateHistory = new VariablesViewStateHistory;
1824 	if (fViewStateHistory->Init() != B_OK)
1825 		throw std::bad_alloc();
1826 }
1827 
1828 
1829 void
1830 VariablesView::_RequestNodeValue(ModelNode* node)
1831 {
1832 	// get the node child and its container
1833 	ValueNodeChild* nodeChild = node->NodeChild();
1834 	ValueNodeContainer* container = nodeChild->Container();
1835 
1836 	BReference<ValueNodeContainer> containerReference(container);
1837 	AutoLocker<ValueNodeContainer> containerLocker(container);
1838 
1839 	if (container == NULL || nodeChild->Container() != container)
1840 		return;
1841 
1842 	// get the value node and check whether its value has not yet been resolved
1843 	ValueNode* valueNode = nodeChild->Node();
1844 	if (valueNode == NULL
1845 		|| valueNode->LocationAndValueResolutionState()
1846 			!= VALUE_NODE_UNRESOLVED) {
1847 		return;
1848 	}
1849 
1850 	BReference<ValueNode> valueNodeReference(valueNode);
1851 	containerLocker.Unlock();
1852 
1853 	// request resolution of the value
1854 	fListener->ValueNodeValueRequested(fStackFrame->GetCpuState(), container,
1855 		valueNode);
1856 }
1857 
1858 
1859 status_t
1860 VariablesView::_GetContextActionsForNode(ModelNode* node,
1861 	ContextActionList* actions)
1862 {
1863 	ValueLocation* location = node->NodeChild()->Location();
1864 
1865 	// if the location's stored somewhere other than in memory,
1866 	// then we won't be able to inspect it this way.
1867 	if (location->PieceAt(0).type != VALUE_PIECE_LOCATION_MEMORY)
1868 		return B_OK;
1869 
1870 	BMessage* message = new BMessage(MSG_SHOW_INSPECTOR_WINDOW);
1871 	if (message == NULL)
1872 		return B_NO_MEMORY;
1873 
1874 	ObjectDeleter<BMessage> messageDeleter(message);
1875 	message->AddUInt64("address", location->PieceAt(0).address);
1876 
1877 	ActionMenuItem* item = new(std::nothrow) ActionMenuItem("Inspect",
1878 		message);
1879 	if (item == NULL)
1880 		return B_NO_MEMORY;
1881 
1882 	messageDeleter.Detach();
1883 	ObjectDeleter<ActionMenuItem> actionDeleter(item);
1884 	if (!actions->AddItem(item))
1885 		return B_NO_MEMORY;
1886 
1887 	actionDeleter.Detach();
1888 	return B_OK;
1889 }
1890 
1891 
1892 void
1893 VariablesView::_FinishContextMenu(bool force)
1894 {
1895 	if (fTableCellContextMenuTracker != NULL) {
1896 		if (!fTableCellContextMenuTracker->FinishMenu(force) || force) {
1897 			fTableCellContextMenuTracker->ReleaseReference();
1898 			fTableCellContextMenuTracker = NULL;
1899 		}
1900 	}
1901 }
1902 
1903 
1904 
1905 void
1906 VariablesView::_SaveViewState() const
1907 {
1908 	if (fThread == NULL || fStackFrame == NULL
1909 		|| fStackFrame->Function() == NULL) {
1910 		return;
1911 	}
1912 
1913 	// get the function ID
1914 	FunctionID* functionID = fStackFrame->Function()->GetFunctionID();
1915 	if (functionID == NULL)
1916 		return;
1917 	BReference<FunctionID> functionIDReference(functionID, true);
1918 
1919 	// create an empty view state
1920 	VariablesViewState* viewState = new(std::nothrow) VariablesViewState;
1921 	if (viewState == NULL)
1922 		return;
1923 	BReference<VariablesViewState> viewStateReference(viewState, true);
1924 
1925 	if (viewState->Init() != B_OK)
1926 		return;
1927 
1928 	// populate it
1929 	TreeTablePath path;
1930 	if (_AddViewStateDescendentNodeInfos(viewState, fVariableTableModel->Root(),
1931 			path) != B_OK) {
1932 		return;
1933 	}
1934 // TODO: Add values!
1935 
1936 	// add the view state to the history
1937 	fViewStateHistory->SetState(fThread->ID(), functionID, viewState);
1938 }
1939 
1940 
1941 void
1942 VariablesView::_RestoreViewState()
1943 {
1944 	if (fPreviousViewState != NULL) {
1945 		fPreviousViewState->ReleaseReference();
1946 		fPreviousViewState = NULL;
1947 	}
1948 
1949 	if (fThread == NULL || fStackFrame == NULL
1950 		|| fStackFrame->Function() == NULL) {
1951 		return;
1952 	}
1953 
1954 	// get the function ID
1955 	FunctionID* functionID = fStackFrame->Function()->GetFunctionID();
1956 	if (functionID == NULL)
1957 		return;
1958 	BReference<FunctionID> functionIDReference(functionID, true);
1959 
1960 	// get the previous view state
1961 	VariablesViewState* viewState = fViewStateHistory->GetState(fThread->ID(),
1962 		functionID);
1963 	if (viewState == NULL)
1964 		return;
1965 
1966 	// apply the view state
1967 	TreeTablePath path;
1968 	_ApplyViewStateDescendentNodeInfos(viewState, fVariableTableModel->Root(),
1969 		path);
1970 }
1971 
1972 
1973 status_t
1974 VariablesView::_AddViewStateDescendentNodeInfos(VariablesViewState* viewState,
1975 	void* parent, TreeTablePath& path) const
1976 {
1977 	int32 childCount = fVariableTableModel->CountChildren(parent);
1978 	for (int32 i = 0; i < childCount; i++) {
1979 		ModelNode* node = (ModelNode*)fVariableTableModel->ChildAt(parent, i);
1980 		if (!path.AddComponent(i))
1981 			return B_NO_MEMORY;
1982 
1983 		// add the node's info
1984 		VariablesViewNodeInfo nodeInfo;
1985 		nodeInfo.SetNodeExpanded(fVariableTable->IsNodeExpanded(path));
1986 
1987 		status_t error = viewState->SetNodeInfo(node->GetVariable()->ID(),
1988 			node->GetPath(), nodeInfo);
1989 		if (error != B_OK)
1990 			return error;
1991 
1992 		// recurse
1993 		error = _AddViewStateDescendentNodeInfos(viewState, node, path);
1994 		if (error != B_OK)
1995 			return error;
1996 
1997 		path.RemoveLastComponent();
1998 	}
1999 
2000 	return B_OK;
2001 }
2002 
2003 
2004 status_t
2005 VariablesView::_ApplyViewStateDescendentNodeInfos(VariablesViewState* viewState,
2006 	void* parent, TreeTablePath& path)
2007 {
2008 	int32 childCount = fVariableTableModel->CountChildren(parent);
2009 	for (int32 i = 0; i < childCount; i++) {
2010 		ModelNode* node = (ModelNode*)fVariableTableModel->ChildAt(parent, i);
2011 		if (!path.AddComponent(i))
2012 			return B_NO_MEMORY;
2013 
2014 		// apply the node's info, if any
2015 		const VariablesViewNodeInfo* nodeInfo = viewState->GetNodeInfo(
2016 			node->GetVariable()->ID(), node->GetPath());
2017 		if (nodeInfo != NULL) {
2018 			fVariableTable->SetNodeExpanded(path, nodeInfo->IsNodeExpanded());
2019 
2020 			// recurse
2021 			status_t error = _ApplyViewStateDescendentNodeInfos(viewState, node,
2022 				path);
2023 			if (error != B_OK)
2024 				return error;
2025 		}
2026 
2027 		path.RemoveLastComponent();
2028 	}
2029 
2030 	return B_OK;
2031 }
2032 
2033 
2034 // #pragma mark - Listener
2035 
2036 
2037 VariablesView::Listener::~Listener()
2038 {
2039 }
2040