From c1034c63fbb8debcff35b726c9aa3c48bbd8d2b2 Mon Sep 17 00:00:00 2001 From: Rene Gollent Date: Fri, 7 Dec 2012 21:15:38 -0500 Subject: [PATCH] Pull a ValueNodeManager class out of VariableTableModel. - The intention is to have a class which handles the actual management of the variable node graph, creating child nodes and such. This way the GUI, CLI and report generator don't have to each reimplement these low-level parts and can instead concentrate on their relevant representations thereof. --- src/apps/debugger/Jamfile | 1 + .../debug_managers/ValueNodeManager.cpp | 234 ++++++++++++++++++ .../debug_managers/ValueNodeManager.h | 54 ++++ 3 files changed, 289 insertions(+) create mode 100644 src/apps/debugger/debug_managers/ValueNodeManager.cpp create mode 100644 src/apps/debugger/debug_managers/ValueNodeManager.h diff --git a/src/apps/debugger/Jamfile b/src/apps/debugger/Jamfile index ac597c6973..1eb7571b33 100644 --- a/src/apps/debugger/Jamfile +++ b/src/apps/debugger/Jamfile @@ -263,6 +263,7 @@ Application Debugger : ValueLoader.cpp ValueNode.cpp ValueNodeContainer.cpp + ValueNodeManager.cpp # value/type_handlers BListTypeHandler.cpp diff --git a/src/apps/debugger/debug_managers/ValueNodeManager.cpp b/src/apps/debugger/debug_managers/ValueNodeManager.cpp new file mode 100644 index 0000000000..4dce046445 --- /dev/null +++ b/src/apps/debugger/debug_managers/ValueNodeManager.cpp @@ -0,0 +1,234 @@ +/* + * Copyright 2012, Rene Gollent, rene@gollent.com. + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + +#include "ValueNodeManager.h" + +#include "AutoLocker.h" + +#include "StackFrame.h" +#include "Thread.h" +#include "TypeHandlerRoster.h" +#include "ValueNode.h" +#include "Variable.h" +#include "VariableValueNodeChild.h" + + +ValueNodeManager::ValueNodeManager() + : + fContainer(NULL), + fStackFrame(NULL), + fThread(NULL) +{ +} + + +ValueNodeManager::~ValueNodeManager() +{ + SetStackFrame(NULL, NULL); +} + + +status_t +ValueNodeManager::SetStackFrame(Thread* thread, + StackFrame* stackFrame) +{ + if (fContainer != NULL) { + AutoLocker containerLocker(fContainer); + + fContainer->RemoveListener(this); + + fContainer->RemoveAllChildren(); + containerLocker.Unlock(); + fContainer->ReleaseReference(); + fContainer = NULL; + } + + fStackFrame = stackFrame; + fThread = thread; + + if (fStackFrame != NULL) { + fContainer = new(std::nothrow) ValueNodeContainer; + if (fContainer == NULL) + return B_NO_MEMORY; + + status_t error = fContainer->Init(); + if (error != B_OK) { + delete fContainer; + fContainer = NULL; + return error; + } + + AutoLocker containerLocker(fContainer); + + fContainer->AddListener(this); + + for (int32 i = 0; Variable* variable = fStackFrame->ParameterAt(i); + i++) { + _AddNode(variable); + } + + for (int32 i = 0; Variable* variable + = fStackFrame->LocalVariableAt(i); i++) { + _AddNode(variable); + } + } + + return B_OK; +} + + +bool +ValueNodeManager::AddListener(ValueNodeContainer::Listener* listener) +{ + return fListeners.AddItem(listener); +} + + +void +ValueNodeManager::RemoveListener(ValueNodeContainer::Listener* listener) +{ + fListeners.RemoveItem(listener); +} + + +void +ValueNodeManager::ValueNodeChanged(ValueNodeChild* nodeChild, + ValueNode* oldNode, ValueNode* newNode) +{ + if (fContainer == NULL) + return; + + AutoLocker containerLocker(fContainer); + + if (oldNode != NULL) + newNode->CreateChildren(); + + for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) + fListeners.ItemAt(i)->ValueNodeChanged(nodeChild, oldNode, newNode); +} + + +void +ValueNodeManager::ValueNodeChildrenCreated(ValueNode* node) +{ + if (fContainer == NULL) + return; + + for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) + fListeners.ItemAt(i)->ValueNodeChildrenCreated(node); +} + + +void +ValueNodeManager::ValueNodeChildrenDeleted(ValueNode* node) +{ + if (fContainer == NULL) + return; + + for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) + fListeners.ItemAt(i)->ValueNodeChildrenDeleted(node); +} + + +void +ValueNodeManager::ValueNodeValueChanged(ValueNode* valueNode) +{ + if (fContainer == NULL) + return; + + AutoLocker containerLocker(fContainer); + + // check whether we know the node + ValueNodeChild* nodeChild = valueNode->NodeChild(); + if (nodeChild == NULL) + return; + + if (valueNode->ChildCreationNeedsValue() + && !valueNode->ChildrenCreated()) { + status_t error = valueNode->CreateChildren(); + if (error != B_OK) + return; + + for (int32 i = 0; i < valueNode->CountChildren(); i++) { + ValueNodeChild* child = valueNode->ChildAt(i); + _CreateValueNode(child); + AddChildNodes(child); + } + } + + for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) + fListeners.ItemAt(i)->ValueNodeValueChanged(valueNode); +} + + +void +ValueNodeManager::_AddNode(Variable* variable) +{ + // create the node child for the variable + ValueNodeChild* nodeChild = new (std::nothrow) VariableValueNodeChild( + variable); + BReference nodeChildReference(nodeChild, true); + if (nodeChild == NULL || !fContainer->AddChild(nodeChild)) { + delete nodeChild; + return; + } + + // automatically add child nodes for the top level nodes + AddChildNodes(nodeChild); +} + + +status_t +ValueNodeManager::_CreateValueNode(ValueNodeChild* nodeChild) +{ + if (nodeChild->Node() != NULL) + return B_OK; + + // create the node + ValueNode* valueNode; + status_t error; + if (nodeChild->IsInternal()) { + error = nodeChild->CreateInternalNode(valueNode); + } else { + error = TypeHandlerRoster::Default()->CreateValueNode(nodeChild, + nodeChild->GetType(), valueNode); + } + + if (error != B_OK) + return error; + + nodeChild->SetNode(valueNode); + valueNode->ReleaseReference(); + + return B_OK; +} + + +status_t +ValueNodeManager::AddChildNodes(ValueNodeChild* nodeChild) +{ + AutoLocker containerLocker(fContainer); + + // create a value node for the value node child, if doesn't have one yet + ValueNode* valueNode = nodeChild->Node(); + if (valueNode == NULL) { + status_t error = _CreateValueNode(nodeChild); + if (error != B_OK) + return error; + valueNode = nodeChild->Node(); + } + + // check if this node requires child creation + // to be deferred until after its location/value have been resolved + if (valueNode->ChildCreationNeedsValue()) + return B_OK; + + // create the children, if not done yet + if (valueNode->ChildrenCreated()) + return B_OK; + + return valueNode->CreateChildren(); +} diff --git a/src/apps/debugger/debug_managers/ValueNodeManager.h b/src/apps/debugger/debug_managers/ValueNodeManager.h new file mode 100644 index 0000000000..603648affb --- /dev/null +++ b/src/apps/debugger/debug_managers/ValueNodeManager.h @@ -0,0 +1,54 @@ +/* + * Copyright 2012, Rene Gollent, rene@gollent.com. + * Distributed under the terms of the MIT License. + */ +#ifndef VALUE_NODE_MANAGER_H +#define VALUE_NODE_MANAGER_H + +#include + +#include "ValueNodeContainer.h" + +class StackFrame; +class Thread; +class Variable; + + +class ValueNodeManager : public BReferenceable, + private ValueNodeContainer::Listener { +public: + ValueNodeManager(); + virtual ~ValueNodeManager(); + + status_t SetStackFrame(Thread* thread, + StackFrame* frame); + + bool AddListener( + ValueNodeContainer::Listener* listener); + void RemoveListener( + ValueNodeContainer::Listener* listener); + + virtual void ValueNodeChanged(ValueNodeChild* nodeChild, + ValueNode* oldNode, ValueNode* newNode); + virtual void ValueNodeChildrenCreated(ValueNode* node); + virtual void ValueNodeChildrenDeleted(ValueNode* node); + virtual void ValueNodeValueChanged(ValueNode* node); + + ValueNodeContainer* GetContainer() const { return fContainer; }; + + status_t AddChildNodes(ValueNodeChild* nodeChild); + +private: + typedef BObjectList ListenerList; + + void _AddNode(Variable* variable); + status_t _CreateValueNode(ValueNodeChild* nodeChild); + +private: + ValueNodeContainer* fContainer; + StackFrame* fStackFrame; + Thread* fThread; + ListenerList fListeners; +}; + +#endif // VALUE_NODE_MANAGER_H