The variables view does now save/restore part of its state when the stack
frame changes. Currently that's only the expanded/collapsed state of the items in the tree view, but that already makes single stepping through code much less annoying. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@33512 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -12,6 +12,7 @@ SEARCH_SOURCE += [ FDirName $(SUBDIR) debug_info ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) debugger_interface ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) elf ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) files ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) gui model ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) gui team_window ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) ids ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) model ] ;
|
||||
@@ -92,6 +93,10 @@ Application Debugger :
|
||||
LocatableFile.cpp
|
||||
SourceFile.cpp
|
||||
|
||||
# gui/model
|
||||
VariablesViewState.cpp
|
||||
VariablesViewStateHistory.cpp
|
||||
|
||||
# gui/team_window
|
||||
ImageFunctionsView.cpp
|
||||
ImageListView.cpp
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "VariablesViewState.h"
|
||||
|
||||
#include <new>
|
||||
|
||||
#include "FunctionID.h"
|
||||
#include "StackFrameValues.h"
|
||||
#include "TypeComponentPath.h"
|
||||
|
||||
|
||||
// #pragma mark - VariablesViewNodeInfo
|
||||
|
||||
|
||||
VariablesViewNodeInfo::VariablesViewNodeInfo()
|
||||
:
|
||||
fNodeExpanded(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
VariablesViewNodeInfo::VariablesViewNodeInfo(const VariablesViewNodeInfo& other)
|
||||
:
|
||||
fNodeExpanded(other.fNodeExpanded)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
VariablesViewNodeInfo&
|
||||
VariablesViewNodeInfo::operator=(const VariablesViewNodeInfo& other)
|
||||
{
|
||||
fNodeExpanded = other.fNodeExpanded;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
VariablesViewNodeInfo::SetNodeExpanded(bool expanded)
|
||||
{
|
||||
fNodeExpanded = expanded;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - Key
|
||||
|
||||
|
||||
struct VariablesViewState::Key {
|
||||
ObjectID* variable;
|
||||
TypeComponentPath* path;
|
||||
|
||||
Key(ObjectID* variable, TypeComponentPath* path)
|
||||
:
|
||||
variable(variable),
|
||||
path(path)
|
||||
{
|
||||
}
|
||||
|
||||
uint32 HashValue() const
|
||||
{
|
||||
return variable->HashValue() ^ path->HashValue();
|
||||
}
|
||||
|
||||
bool operator==(const Key& other) const
|
||||
{
|
||||
return *variable == *other.variable && *path == *other.path;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - InfoEntry
|
||||
|
||||
|
||||
struct VariablesViewState::InfoEntry : Key, VariablesViewNodeInfo {
|
||||
InfoEntry* next;
|
||||
|
||||
InfoEntry(ObjectID* variable, TypeComponentPath* path)
|
||||
:
|
||||
Key(variable, path)
|
||||
{
|
||||
variable->AcquireReference();
|
||||
path->AcquireReference();
|
||||
}
|
||||
|
||||
~InfoEntry()
|
||||
{
|
||||
variable->ReleaseReference();
|
||||
path->ReleaseReference();
|
||||
}
|
||||
|
||||
void SetInfo(const VariablesViewNodeInfo& info)
|
||||
{
|
||||
VariablesViewNodeInfo::operator=(info);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct VariablesViewState::InfoEntryHashDefinition {
|
||||
typedef Key KeyType;
|
||||
typedef InfoEntry ValueType;
|
||||
|
||||
size_t HashKey(const Key& key) const
|
||||
{
|
||||
return key.HashValue();
|
||||
}
|
||||
|
||||
size_t Hash(const InfoEntry* value) const
|
||||
{
|
||||
return value->HashValue();
|
||||
}
|
||||
|
||||
bool Compare(const Key& key, const InfoEntry* value) const
|
||||
{
|
||||
return key == *value;
|
||||
}
|
||||
|
||||
InfoEntry*& GetLink(InfoEntry* value) const
|
||||
{
|
||||
return value->next;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
VariablesViewState::VariablesViewState()
|
||||
:
|
||||
fNodeInfos(NULL),
|
||||
fValues(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
VariablesViewState::~VariablesViewState()
|
||||
{
|
||||
_Cleanup();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
VariablesViewState::Init()
|
||||
{
|
||||
fNodeInfos = new(std::nothrow) NodeInfoTable;
|
||||
if (fNodeInfos == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
return fNodeInfos->Init();
|
||||
}
|
||||
|
||||
void
|
||||
VariablesViewState::SetValues(StackFrameValues* values)
|
||||
{
|
||||
if (fValues == values)
|
||||
return;
|
||||
|
||||
if (fValues != NULL)
|
||||
fValues->ReleaseReference();
|
||||
|
||||
fValues = values;
|
||||
|
||||
if (fValues != NULL)
|
||||
fValues->AcquireReference();
|
||||
}
|
||||
|
||||
|
||||
const VariablesViewNodeInfo*
|
||||
VariablesViewState::GetNodeInfo(ObjectID* variable,
|
||||
const TypeComponentPath* path) const
|
||||
{
|
||||
return fNodeInfos->Lookup(Key(variable, (TypeComponentPath*)path));
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
VariablesViewState::SetNodeInfo(ObjectID* variable, TypeComponentPath* path,
|
||||
const VariablesViewNodeInfo& info)
|
||||
{
|
||||
InfoEntry* entry = fNodeInfos->Lookup(Key(variable, path));
|
||||
if (entry == NULL) {
|
||||
entry = new(std::nothrow) InfoEntry(variable, path);
|
||||
if (entry == NULL)
|
||||
return B_NO_MEMORY;
|
||||
fNodeInfos->Insert(entry);
|
||||
}
|
||||
|
||||
entry->SetInfo(info);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
VariablesViewState::_Cleanup()
|
||||
{
|
||||
if (fNodeInfos != NULL) {
|
||||
InfoEntry* entry = fNodeInfos->Clear(true);
|
||||
|
||||
while (entry != NULL) {
|
||||
InfoEntry* next = entry->next;
|
||||
delete entry;
|
||||
entry = next;
|
||||
}
|
||||
|
||||
delete fNodeInfos;
|
||||
fNodeInfos = NULL;
|
||||
}
|
||||
|
||||
SetValues(NULL);
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef VARIABLES_VIEW_STATE_H
|
||||
#define VARIABLES_VIEW_STATE_H
|
||||
|
||||
|
||||
#include <Referenceable.h>
|
||||
#include <util/OpenHashTable.h>
|
||||
|
||||
|
||||
class ObjectID;
|
||||
class StackFrameValues;
|
||||
class TypeComponentPath;
|
||||
|
||||
|
||||
class VariablesViewNodeInfo {
|
||||
public:
|
||||
VariablesViewNodeInfo();
|
||||
VariablesViewNodeInfo(
|
||||
const VariablesViewNodeInfo& other);
|
||||
|
||||
VariablesViewNodeInfo& operator=(
|
||||
const VariablesViewNodeInfo& other);
|
||||
|
||||
bool IsNodeExpanded() const
|
||||
{ return fNodeExpanded; }
|
||||
void SetNodeExpanded(bool expanded);
|
||||
|
||||
private:
|
||||
bool fNodeExpanded;
|
||||
};
|
||||
|
||||
|
||||
class VariablesViewState : public Referenceable {
|
||||
public:
|
||||
VariablesViewState();
|
||||
virtual ~VariablesViewState();
|
||||
|
||||
status_t Init();
|
||||
|
||||
StackFrameValues* Values() const
|
||||
{ return fValues; }
|
||||
void SetValues(StackFrameValues* values);
|
||||
|
||||
const VariablesViewNodeInfo* GetNodeInfo(ObjectID* variable,
|
||||
const TypeComponentPath* path) const;
|
||||
inline const VariablesViewNodeInfo* GetNodeInfo(ObjectID* variable,
|
||||
const TypeComponentPath& path) const;
|
||||
|
||||
status_t SetNodeInfo(ObjectID* variable,
|
||||
TypeComponentPath* path,
|
||||
const VariablesViewNodeInfo& info);
|
||||
// requires an on-heap path
|
||||
|
||||
private:
|
||||
struct Key;
|
||||
struct InfoEntry;
|
||||
struct InfoEntryHashDefinition;
|
||||
|
||||
typedef BOpenHashTable<InfoEntryHashDefinition> NodeInfoTable;
|
||||
|
||||
private:
|
||||
void _Cleanup();
|
||||
|
||||
private:
|
||||
NodeInfoTable* fNodeInfos;
|
||||
StackFrameValues* fValues;
|
||||
};
|
||||
|
||||
|
||||
const VariablesViewNodeInfo*
|
||||
VariablesViewState::GetNodeInfo(ObjectID* variable,
|
||||
const TypeComponentPath& path) const
|
||||
{
|
||||
return GetNodeInfo(variable, &path);
|
||||
}
|
||||
|
||||
|
||||
#endif // VARIABLES_VIEW_STATE_H
|
||||
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "VariablesViewStateHistory.h"
|
||||
|
||||
#include <new>
|
||||
|
||||
#include "FunctionID.h"
|
||||
#include "VariablesViewState.h"
|
||||
|
||||
|
||||
// #pragma mark - Key
|
||||
|
||||
|
||||
struct VariablesViewStateHistory::Key {
|
||||
thread_id threadID;
|
||||
FunctionID* functionID;
|
||||
|
||||
Key(thread_id threadID, FunctionID* functionID)
|
||||
:
|
||||
threadID(threadID),
|
||||
functionID(functionID)
|
||||
{
|
||||
}
|
||||
|
||||
uint32 HashValue() const
|
||||
{
|
||||
return functionID->HashValue() ^ threadID;
|
||||
}
|
||||
|
||||
bool operator==(const Key& other) const
|
||||
{
|
||||
return threadID == other.threadID && *functionID == *other.functionID;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - StateEntry
|
||||
|
||||
|
||||
struct VariablesViewStateHistory::StateEntry : Key, VariablesViewNodeInfo {
|
||||
StateEntry* next;
|
||||
VariablesViewState* state;
|
||||
|
||||
StateEntry(thread_id threadID, FunctionID* functionID)
|
||||
:
|
||||
Key(threadID, functionID),
|
||||
state(NULL)
|
||||
{
|
||||
functionID->AcquireReference();
|
||||
}
|
||||
|
||||
~StateEntry()
|
||||
{
|
||||
functionID->ReleaseReference();
|
||||
if (state != NULL)
|
||||
state->ReleaseReference();
|
||||
}
|
||||
|
||||
void SetState(VariablesViewState* state)
|
||||
{
|
||||
if (state == this->state)
|
||||
return;
|
||||
|
||||
if (state != NULL)
|
||||
state->AcquireReference();
|
||||
|
||||
if (this->state != NULL)
|
||||
this->state->ReleaseReference();
|
||||
|
||||
this->state = state;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct VariablesViewStateHistory::StateEntryHashDefinition {
|
||||
typedef Key KeyType;
|
||||
typedef StateEntry ValueType;
|
||||
|
||||
size_t HashKey(const Key& key) const
|
||||
{
|
||||
return key.HashValue();
|
||||
}
|
||||
|
||||
size_t Hash(const StateEntry* value) const
|
||||
{
|
||||
return HashKey(*value);
|
||||
}
|
||||
|
||||
bool Compare(const Key& key, const StateEntry* value) const
|
||||
{
|
||||
return key == *value;
|
||||
}
|
||||
|
||||
StateEntry*& GetLink(StateEntry* value) const
|
||||
{
|
||||
return value->next;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
VariablesViewStateHistory::VariablesViewStateHistory()
|
||||
:
|
||||
fStates(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
VariablesViewStateHistory::~VariablesViewStateHistory()
|
||||
{
|
||||
if (fStates != NULL) {
|
||||
StateEntry* entry = fStates->Clear(true);
|
||||
|
||||
while (entry != NULL) {
|
||||
StateEntry* next = entry->next;
|
||||
delete entry;
|
||||
entry = next;
|
||||
}
|
||||
|
||||
delete fStates;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
VariablesViewStateHistory::Init()
|
||||
{
|
||||
fStates = new(std::nothrow) StateTable;
|
||||
if (fStates == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
return fStates->Init();
|
||||
}
|
||||
|
||||
|
||||
VariablesViewState*
|
||||
VariablesViewStateHistory::GetState(thread_id threadID, FunctionID* functionID)
|
||||
const
|
||||
{
|
||||
// first try an exact match with the thread ID
|
||||
if (threadID >= 0) {
|
||||
StateEntry* stateEntry = fStates->Lookup(Key(threadID, functionID));
|
||||
if (stateEntry != NULL)
|
||||
return stateEntry->state;
|
||||
}
|
||||
|
||||
// just match the function ID
|
||||
StateEntry* stateEntry = fStates->Lookup(Key(-1, functionID));
|
||||
return stateEntry != NULL ? stateEntry->state : NULL;
|
||||
}
|
||||
|
||||
|
||||
VariablesViewState*
|
||||
VariablesViewStateHistory::GetState(FunctionID* functionID) const
|
||||
{
|
||||
StateEntry* stateEntry = fStates->Lookup(Key(-1, functionID));
|
||||
return stateEntry != NULL ? stateEntry->state : NULL;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
VariablesViewStateHistory::SetState(thread_id threadID, FunctionID* functionID,
|
||||
VariablesViewState* state)
|
||||
{
|
||||
// Make sure the default entry for the function exists.
|
||||
StateEntry* defaultEntry = fStates->Lookup(Key(-1, functionID));
|
||||
bool newDefaultEntry = false;
|
||||
|
||||
if (defaultEntry == NULL) {
|
||||
defaultEntry = new(std::nothrow) StateEntry(-1, functionID);
|
||||
if (defaultEntry == NULL)
|
||||
return B_NO_MEMORY;
|
||||
fStates->Insert(defaultEntry);
|
||||
newDefaultEntry = true;
|
||||
}
|
||||
|
||||
// If we have a valid thread ID, make sure the respective entry for the
|
||||
// function exists.
|
||||
StateEntry* threadEntry = NULL;
|
||||
if (threadID >= 0) {
|
||||
threadEntry = fStates->Lookup(Key(threadID, functionID));
|
||||
|
||||
if (threadEntry == NULL) {
|
||||
threadEntry = new(std::nothrow) StateEntry(threadID, functionID);
|
||||
if (threadEntry == NULL) {
|
||||
if (newDefaultEntry) {
|
||||
fStates->Remove(defaultEntry);
|
||||
delete defaultEntry;
|
||||
}
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
fStates->Insert(threadEntry);
|
||||
}
|
||||
}
|
||||
|
||||
defaultEntry->SetState(state);
|
||||
if (threadEntry != NULL)
|
||||
threadEntry->SetState(state);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef VARIABLES_VIEW_STATE_HISTORY_H
|
||||
#define VARIABLES_VIEW_STATE_HISTORY_H
|
||||
|
||||
|
||||
#include <util/OpenHashTable.h>
|
||||
|
||||
|
||||
class FunctionID;
|
||||
class VariablesViewState;
|
||||
|
||||
|
||||
class VariablesViewStateHistory {
|
||||
public:
|
||||
VariablesViewStateHistory();
|
||||
virtual ~VariablesViewStateHistory();
|
||||
|
||||
status_t Init();
|
||||
|
||||
VariablesViewState* GetState(thread_id threadID,
|
||||
FunctionID* functionID) const;
|
||||
VariablesViewState* GetState(FunctionID* functionID) const;
|
||||
|
||||
status_t SetState(thread_id threadID,
|
||||
FunctionID* functionID,
|
||||
VariablesViewState* state);
|
||||
|
||||
private:
|
||||
struct Key;
|
||||
struct StateEntry;
|
||||
struct StateEntryHashDefinition;
|
||||
|
||||
typedef BOpenHashTable<StateEntryHashDefinition> StateTable;
|
||||
|
||||
private:
|
||||
StateTable* fStates;
|
||||
};
|
||||
|
||||
|
||||
#endif // VARIABLES_VIEW_STATE_HISTORY_H
|
||||
@@ -15,6 +15,8 @@
|
||||
#include "table/TableColumns.h"
|
||||
|
||||
#include "Architecture.h"
|
||||
#include "FunctionID.h"
|
||||
#include "FunctionInstance.h"
|
||||
#include "StackFrame.h"
|
||||
#include "StackFrameValues.h"
|
||||
#include "Team.h"
|
||||
@@ -22,6 +24,8 @@
|
||||
#include "Tracing.h"
|
||||
#include "TypeComponentPath.h"
|
||||
#include "Variable.h"
|
||||
#include "VariablesViewState.h"
|
||||
#include "VariablesViewStateHistory.h"
|
||||
|
||||
|
||||
enum {
|
||||
@@ -749,6 +753,8 @@ VariablesView::VariablesView(Listener* listener)
|
||||
fStackFrame(NULL),
|
||||
fVariableTable(NULL),
|
||||
fVariableTableModel(NULL),
|
||||
fPreviousViewState(NULL),
|
||||
fViewStateHistory(NULL),
|
||||
fListener(listener)
|
||||
{
|
||||
SetName("Variables");
|
||||
@@ -759,6 +765,9 @@ VariablesView::~VariablesView()
|
||||
{
|
||||
SetStackFrame(NULL, NULL);
|
||||
fVariableTable->SetTreeTableModel(NULL);
|
||||
if (fPreviousViewState != NULL)
|
||||
fPreviousViewState->ReleaseReference();
|
||||
delete fViewStateHistory;
|
||||
delete fVariableTableModel;
|
||||
}
|
||||
|
||||
@@ -785,6 +794,8 @@ VariablesView::SetStackFrame(Thread* thread, StackFrame* stackFrame)
|
||||
if (thread == fThread && stackFrame == fStackFrame)
|
||||
return;
|
||||
|
||||
_SaveViewState();
|
||||
|
||||
if (fThread != NULL)
|
||||
fThread->ReleaseReference();
|
||||
if (fStackFrame != NULL)
|
||||
@@ -812,6 +823,8 @@ VariablesView::SetStackFrame(Thread* thread, StackFrame* stackFrame)
|
||||
_RequestVariableValue(variable);
|
||||
}
|
||||
}
|
||||
|
||||
_RestoreViewState();
|
||||
}
|
||||
|
||||
|
||||
@@ -868,6 +881,10 @@ VariablesView::_Init()
|
||||
fVariableTable->SetTreeTableModel(fVariableTableModel);
|
||||
|
||||
fVariableTable->AddTreeTableListener(this);
|
||||
|
||||
fViewStateHistory = new VariablesViewStateHistory;
|
||||
if (fViewStateHistory->Init() != B_OK)
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
|
||||
@@ -887,6 +904,131 @@ VariablesView::_RequestVariableValue(Variable* variable)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
VariablesView::_SaveViewState() const
|
||||
{
|
||||
if (fThread == NULL || fStackFrame == NULL)
|
||||
return;
|
||||
|
||||
// get the function ID
|
||||
FunctionID* functionID = fStackFrame->Function()->GetFunctionID();
|
||||
if (functionID == NULL)
|
||||
return;
|
||||
Reference<FunctionID> functionIDReference(functionID, true);
|
||||
|
||||
// create an empty view state
|
||||
VariablesViewState* viewState = new(std::nothrow) VariablesViewState;
|
||||
if (viewState == NULL)
|
||||
return;
|
||||
Reference<VariablesViewState> viewStateReference(viewState, true);
|
||||
|
||||
if (viewState->Init() != B_OK)
|
||||
return;
|
||||
|
||||
// populate it
|
||||
TreeTablePath path;
|
||||
if (_AddViewStateDescendentNodeInfos(viewState, fVariableTableModel->Root(),
|
||||
path) != B_OK) {
|
||||
return;
|
||||
}
|
||||
// TODO: Add values!
|
||||
|
||||
// add the view state to the history
|
||||
fViewStateHistory->SetState(fThread->ID(), functionID, viewState);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
VariablesView::_RestoreViewState()
|
||||
{
|
||||
if (fPreviousViewState != NULL) {
|
||||
fPreviousViewState->ReleaseReference();
|
||||
fPreviousViewState = NULL;
|
||||
}
|
||||
|
||||
if (fThread == NULL || fStackFrame == NULL)
|
||||
return;
|
||||
|
||||
// get the function ID
|
||||
FunctionID* functionID = fStackFrame->Function()->GetFunctionID();
|
||||
if (functionID == NULL)
|
||||
return;
|
||||
Reference<FunctionID> functionIDReference(functionID, true);
|
||||
|
||||
// get the previous view state
|
||||
VariablesViewState* viewState = fViewStateHistory->GetState(fThread->ID(),
|
||||
functionID);
|
||||
if (viewState == NULL)
|
||||
return;
|
||||
|
||||
// apply the view state
|
||||
TreeTablePath path;
|
||||
_ApplyViewStateDescendentNodeInfos(viewState, fVariableTableModel->Root(),
|
||||
path);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
VariablesView::_AddViewStateDescendentNodeInfos(VariablesViewState* viewState,
|
||||
void* parent, TreeTablePath& path) const
|
||||
{
|
||||
int32 childCount = fVariableTableModel->CountChildren(parent);
|
||||
for (int32 i = 0; i < childCount; i++) {
|
||||
ValueNode* node = (ValueNode*)fVariableTableModel->ChildAt(parent, i);
|
||||
if (!path.AddComponent(i))
|
||||
return B_NO_MEMORY;
|
||||
|
||||
// add the node's info
|
||||
VariablesViewNodeInfo nodeInfo;
|
||||
nodeInfo.SetNodeExpanded(fVariableTable->IsNodeExpanded(path));
|
||||
|
||||
status_t error = viewState->SetNodeInfo(node->GetVariable()->ID(),
|
||||
node->Path(), nodeInfo);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// recurse
|
||||
error = _AddViewStateDescendentNodeInfos(viewState, node, path);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
path.RemoveLastComponent();
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
VariablesView::_ApplyViewStateDescendentNodeInfos(VariablesViewState* viewState,
|
||||
void* parent, TreeTablePath& path)
|
||||
{
|
||||
int32 childCount = fVariableTableModel->CountChildren(parent);
|
||||
for (int32 i = 0; i < childCount; i++) {
|
||||
ValueNode* node = (ValueNode*)fVariableTableModel->ChildAt(parent, i);
|
||||
if (!path.AddComponent(i))
|
||||
return B_NO_MEMORY;
|
||||
|
||||
// apply the node's info, if any
|
||||
const VariablesViewNodeInfo* nodeInfo = viewState->GetNodeInfo(
|
||||
node->GetVariable()->ID(), node->Path());
|
||||
if (nodeInfo != NULL) {
|
||||
fVariableTable->SetNodeExpanded(path, nodeInfo->IsNodeExpanded());
|
||||
|
||||
// recurse
|
||||
status_t error = _ApplyViewStateDescendentNodeInfos(viewState, node,
|
||||
path);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
}
|
||||
|
||||
path.RemoveLastComponent();
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - Listener
|
||||
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@ class StackFrame;
|
||||
class Thread;
|
||||
class TypeComponentPath;
|
||||
class Variable;
|
||||
class VariablesViewState;
|
||||
class VariablesViewStateHistory;
|
||||
|
||||
|
||||
class VariablesView : public BGroupView, private TreeTableListener {
|
||||
@@ -49,11 +51,22 @@ private:
|
||||
|
||||
void _RequestVariableValue(Variable* variable);
|
||||
|
||||
void _SaveViewState() const;
|
||||
void _RestoreViewState();
|
||||
status_t _AddViewStateDescendentNodeInfos(
|
||||
VariablesViewState* viewState, void* parent,
|
||||
TreeTablePath& path) const;
|
||||
status_t _ApplyViewStateDescendentNodeInfos(
|
||||
VariablesViewState* viewState, void* parent,
|
||||
TreeTablePath& path);
|
||||
|
||||
private:
|
||||
Thread* fThread;
|
||||
StackFrame* fStackFrame;
|
||||
TreeTable* fVariableTable;
|
||||
VariableTableModel* fVariableTableModel;
|
||||
VariablesViewState* fPreviousViewState;
|
||||
VariablesViewStateHistory* fViewStateHistory;
|
||||
Listener* fListener;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user