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) debugger_interface ] ;
|
||||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) elf ] ;
|
SEARCH_SOURCE += [ FDirName $(SUBDIR) elf ] ;
|
||||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) files ] ;
|
SEARCH_SOURCE += [ FDirName $(SUBDIR) files ] ;
|
||||||
|
SEARCH_SOURCE += [ FDirName $(SUBDIR) gui model ] ;
|
||||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) gui team_window ] ;
|
SEARCH_SOURCE += [ FDirName $(SUBDIR) gui team_window ] ;
|
||||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) ids ] ;
|
SEARCH_SOURCE += [ FDirName $(SUBDIR) ids ] ;
|
||||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) model ] ;
|
SEARCH_SOURCE += [ FDirName $(SUBDIR) model ] ;
|
||||||
@@ -92,6 +93,10 @@ Application Debugger :
|
|||||||
LocatableFile.cpp
|
LocatableFile.cpp
|
||||||
SourceFile.cpp
|
SourceFile.cpp
|
||||||
|
|
||||||
|
# gui/model
|
||||||
|
VariablesViewState.cpp
|
||||||
|
VariablesViewStateHistory.cpp
|
||||||
|
|
||||||
# gui/team_window
|
# gui/team_window
|
||||||
ImageFunctionsView.cpp
|
ImageFunctionsView.cpp
|
||||||
ImageListView.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 "table/TableColumns.h"
|
||||||
|
|
||||||
#include "Architecture.h"
|
#include "Architecture.h"
|
||||||
|
#include "FunctionID.h"
|
||||||
|
#include "FunctionInstance.h"
|
||||||
#include "StackFrame.h"
|
#include "StackFrame.h"
|
||||||
#include "StackFrameValues.h"
|
#include "StackFrameValues.h"
|
||||||
#include "Team.h"
|
#include "Team.h"
|
||||||
@@ -22,6 +24,8 @@
|
|||||||
#include "Tracing.h"
|
#include "Tracing.h"
|
||||||
#include "TypeComponentPath.h"
|
#include "TypeComponentPath.h"
|
||||||
#include "Variable.h"
|
#include "Variable.h"
|
||||||
|
#include "VariablesViewState.h"
|
||||||
|
#include "VariablesViewStateHistory.h"
|
||||||
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@@ -749,6 +753,8 @@ VariablesView::VariablesView(Listener* listener)
|
|||||||
fStackFrame(NULL),
|
fStackFrame(NULL),
|
||||||
fVariableTable(NULL),
|
fVariableTable(NULL),
|
||||||
fVariableTableModel(NULL),
|
fVariableTableModel(NULL),
|
||||||
|
fPreviousViewState(NULL),
|
||||||
|
fViewStateHistory(NULL),
|
||||||
fListener(listener)
|
fListener(listener)
|
||||||
{
|
{
|
||||||
SetName("Variables");
|
SetName("Variables");
|
||||||
@@ -759,6 +765,9 @@ VariablesView::~VariablesView()
|
|||||||
{
|
{
|
||||||
SetStackFrame(NULL, NULL);
|
SetStackFrame(NULL, NULL);
|
||||||
fVariableTable->SetTreeTableModel(NULL);
|
fVariableTable->SetTreeTableModel(NULL);
|
||||||
|
if (fPreviousViewState != NULL)
|
||||||
|
fPreviousViewState->ReleaseReference();
|
||||||
|
delete fViewStateHistory;
|
||||||
delete fVariableTableModel;
|
delete fVariableTableModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -785,6 +794,8 @@ VariablesView::SetStackFrame(Thread* thread, StackFrame* stackFrame)
|
|||||||
if (thread == fThread && stackFrame == fStackFrame)
|
if (thread == fThread && stackFrame == fStackFrame)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
_SaveViewState();
|
||||||
|
|
||||||
if (fThread != NULL)
|
if (fThread != NULL)
|
||||||
fThread->ReleaseReference();
|
fThread->ReleaseReference();
|
||||||
if (fStackFrame != NULL)
|
if (fStackFrame != NULL)
|
||||||
@@ -812,6 +823,8 @@ VariablesView::SetStackFrame(Thread* thread, StackFrame* stackFrame)
|
|||||||
_RequestVariableValue(variable);
|
_RequestVariableValue(variable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_RestoreViewState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -868,6 +881,10 @@ VariablesView::_Init()
|
|||||||
fVariableTable->SetTreeTableModel(fVariableTableModel);
|
fVariableTable->SetTreeTableModel(fVariableTableModel);
|
||||||
|
|
||||||
fVariableTable->AddTreeTableListener(this);
|
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
|
// #pragma mark - Listener
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ class StackFrame;
|
|||||||
class Thread;
|
class Thread;
|
||||||
class TypeComponentPath;
|
class TypeComponentPath;
|
||||||
class Variable;
|
class Variable;
|
||||||
|
class VariablesViewState;
|
||||||
|
class VariablesViewStateHistory;
|
||||||
|
|
||||||
|
|
||||||
class VariablesView : public BGroupView, private TreeTableListener {
|
class VariablesView : public BGroupView, private TreeTableListener {
|
||||||
@@ -49,11 +51,22 @@ private:
|
|||||||
|
|
||||||
void _RequestVariableValue(Variable* variable);
|
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:
|
private:
|
||||||
Thread* fThread;
|
Thread* fThread;
|
||||||
StackFrame* fStackFrame;
|
StackFrame* fStackFrame;
|
||||||
TreeTable* fVariableTable;
|
TreeTable* fVariableTable;
|
||||||
VariableTableModel* fVariableTableModel;
|
VariableTableModel* fVariableTableModel;
|
||||||
|
VariablesViewState* fPreviousViewState;
|
||||||
|
VariablesViewStateHistory* fViewStateHistory;
|
||||||
Listener* fListener;
|
Listener* fListener;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user