Debugger: Implement #9946.

TableCellValueRenderer{Utils}:
- The rendering calls now take a boolean indicating if the value
  being rendered differs from its previous state. This is taken
  into account by rendering it in a different color to indicate
  the change. Adjust all implementing subclasses accordingly.

VariablesView::ModelNode:
- Now stores the previous value of the corresponding value node,
  and can be queried if its value has changed. Used by renderers.

VariablesView::_{Add,Apply}ViewStateDescendentInfos():
- When walking the model, also store/restore the values of nodes in the
  history.

In summation of all the above changes, when stepping through a function,
we now display values that have changed since the last step, or that have
appeared for the first time in a different color.
This commit is contained in:
Rene Gollent
2014-11-01 18:51:57 -04:00
parent f40556afab
commit b6c4fc962c
15 changed files with 129 additions and 38 deletions
@@ -108,13 +108,15 @@ public:
fNodeChild(nodeChild), fNodeChild(nodeChild),
fVariable(variable), fVariable(variable),
fValue(NULL), fValue(NULL),
fPreviousValue(),
fValueHandler(NULL), fValueHandler(NULL),
fTableCellRenderer(NULL), fTableCellRenderer(NULL),
fLastRendererSettings(), fLastRendererSettings(),
fCastedType(NULL), fCastedType(NULL),
fComponentPath(NULL), fComponentPath(NULL),
fIsPresentationNode(isPresentationNode), fIsPresentationNode(isPresentationNode),
fHidden(false) fHidden(false),
fValueChanged(false)
{ {
fNodeChild->AcquireReference(); fNodeChild->AcquireReference();
} }
@@ -202,6 +204,18 @@ public:
if (fValue != NULL) if (fValue != NULL)
fValue->AcquireReference(); fValue->AcquireReference();
_CompareValues();
}
const BVariant& PreviousValue() const
{
return fPreviousValue;
}
void SetPreviousValue(const BVariant& value)
{
fPreviousValue = value;
} }
Type* GetCastedType() const Type* GetCastedType() const
@@ -288,6 +302,11 @@ public:
fHidden = hidden; fHidden = hidden;
} }
bool ValueChanged() const
{
return fValueChanged;
}
int32 CountChildren() const int32 CountChildren() const
{ {
return fChildren.CountItems(); return fChildren.CountItems();
@@ -332,11 +351,24 @@ public:
private: private:
typedef BObjectList<ModelNode> ChildList; typedef BObjectList<ModelNode> ChildList;
private:
void _CompareValues()
{
if (fValue == NULL)
fValueChanged = false;
else {
BVariant newValue;
fValue->ToVariant(newValue);
fValueChanged = (fPreviousValue != newValue);
}
}
private: private:
ModelNode* fParent; ModelNode* fParent;
ValueNodeChild* fNodeChild; ValueNodeChild* fNodeChild;
Variable* fVariable; Variable* fVariable;
Value* fValue; Value* fValue;
BVariant fPreviousValue;
ValueHandler* fValueHandler; ValueHandler* fValueHandler;
TableCellValueRenderer* fTableCellRenderer; TableCellValueRenderer* fTableCellRenderer;
BMessage fLastRendererSettings; BMessage fLastRendererSettings;
@@ -345,6 +377,7 @@ private:
TypeComponentPath* fComponentPath; TypeComponentPath* fComponentPath;
bool fIsPresentationNode; bool fIsPresentationNode;
bool fHidden; bool fHidden;
bool fValueChanged;
public: public:
ModelNode* fNext; ModelNode* fNext;
@@ -373,8 +406,8 @@ protected:
ModelNode* node = dynamic_cast<ModelNode*>(value.ToReferenceable()); ModelNode* node = dynamic_cast<ModelNode*>(value.ToReferenceable());
if (node != NULL && node->GetValue() != NULL if (node != NULL && node->GetValue() != NULL
&& node->TableCellRenderer() != NULL) { && node->TableCellRenderer() != NULL) {
node->TableCellRenderer()->RenderValue(node->GetValue(), rect, node->TableCellRenderer()->RenderValue(node->GetValue(),
targetView); node->ValueChanged(), rect, targetView);
return; return;
} }
} else if (value.Type() == B_STRING_TYPE) { } else if (value.Type() == B_STRING_TYPE) {
@@ -1102,6 +1135,8 @@ VariablesView::VariableTableModel::ValueNodeValueChanged(ValueNode* valueNode)
settings->RestoreValues(modelNode->GetLastRendererSettings()); settings->RestoreValues(modelNode->GetLastRendererSettings());
} }
// notify table model listeners // notify table model listeners
NotifyNodeChanged(modelNode); NotifyNodeChanged(modelNode);
} }
@@ -2168,6 +2203,14 @@ VariablesView::_SaveViewState() const
return; return;
BReference<FunctionID> functionIDReference(functionID, true); BReference<FunctionID> functionIDReference(functionID, true);
StackFrameValues* values = new(std::nothrow) StackFrameValues;
if (values == NULL)
return;
BReference<StackFrameValues> valuesReference(values, true);
if (values->Init() != B_OK)
return;
// create an empty view state // create an empty view state
VariablesViewState* viewState = new(std::nothrow) VariablesViewState; VariablesViewState* viewState = new(std::nothrow) VariablesViewState;
if (viewState == NULL) if (viewState == NULL)
@@ -2177,13 +2220,14 @@ VariablesView::_SaveViewState() const
if (viewState->Init() != B_OK) if (viewState->Init() != B_OK)
return; return;
viewState->SetValues(values);
// populate it // populate it
TreeTablePath path; TreeTablePath path;
if (_AddViewStateDescendentNodeInfos(viewState, fVariableTableModel->Root(), if (_AddViewStateDescendentNodeInfos(viewState,
path) != B_OK) { fVariableTableModel->Root(), path) != B_OK) {
return; return;
} }
// TODO: Add values!
// add the view state to the history // add the view state to the history
fViewStateHistory->SetState(fThread->ID(), functionID, viewState); fViewStateHistory->SetState(fThread->ID(), functionID, viewState);
@@ -2243,11 +2287,23 @@ VariablesView::_AddViewStateDescendentNodeInfos(VariablesViewState* viewState,
nodeInfo.SetRendererSettings(settings->Message()); nodeInfo.SetRendererSettings(settings->Message());
} }
status_t error = viewState->SetNodeInfo(node->GetVariable()->ID(), ObjectID* id = node->GetVariable()->ID();
node->GetPath(), nodeInfo); TypeComponentPath* componentPath = node->GetPath();
status_t error = viewState->SetNodeInfo(id, componentPath, nodeInfo);
if (error != B_OK) if (error != B_OK)
return error; return error;
Value* value = node->GetValue();
if (value != NULL) {
BVariant variableValueData;
if (value->ToVariant(variableValueData))
error = viewState->Values()->SetValue(id, componentPath,
variableValueData);
if (error != B_OK)
return error;
}
// recurse // recurse
error = _AddViewStateDescendentNodeInfos(viewState, node, path); error = _AddViewStateDescendentNodeInfos(viewState, node, path);
if (error != B_OK) if (error != B_OK)
@@ -2271,8 +2327,10 @@ VariablesView::_ApplyViewStateDescendentNodeInfos(VariablesViewState* viewState,
return B_NO_MEMORY; return B_NO_MEMORY;
// apply the node's info, if any // apply the node's info, if any
ObjectID* objectID = node->GetVariable()->ID();
TypeComponentPath* componentPath = node->GetPath();
const VariablesViewNodeInfo* nodeInfo = viewState->GetNodeInfo( const VariablesViewNodeInfo* nodeInfo = viewState->GetNodeInfo(
node->GetVariable()->ID(), node->GetPath()); objectID, componentPath);
if (nodeInfo != NULL) { if (nodeInfo != NULL) {
// NB: if the node info indicates that the node in question // NB: if the node info indicates that the node in question
// was being cast to a different type, this *must* be applied // was being cast to a different type, this *must* be applied
@@ -2295,6 +2353,12 @@ VariablesView::_ApplyViewStateDescendentNodeInfos(VariablesViewState* viewState,
fVariableTable->SetNodeExpanded(path, nodeInfo->IsNodeExpanded()); fVariableTable->SetNodeExpanded(path, nodeInfo->IsNodeExpanded());
BVariant previousValue;
if (viewState->Values()->GetValue(objectID, componentPath,
previousValue)) {
node->SetPreviousValue(previousValue);
}
// recurse // recurse
status_t error = _ApplyViewStateDescendentNodeInfos(viewState, node, status_t error = _ApplyViewStateDescendentNodeInfos(viewState, node,
path); path);
@@ -16,6 +16,7 @@ class ActionMenuItem;
class CpuState; class CpuState;
class SettingsMenu; class SettingsMenu;
class StackFrame; class StackFrame;
class StackFrameValues;
class Thread; class Thread;
class Type; class Type;
class TypeComponentPath; class TypeComponentPath;
@@ -81,10 +82,12 @@ private:
void _SaveViewState() const; void _SaveViewState() const;
void _RestoreViewState(); void _RestoreViewState();
status_t _AddViewStateDescendentNodeInfos( status_t _AddViewStateDescendentNodeInfos(
VariablesViewState* viewState, void* parent, VariablesViewState* viewState,
void* parent,
TreeTablePath& path) const; TreeTablePath& path) const;
status_t _ApplyViewStateDescendentNodeInfos( status_t _ApplyViewStateDescendentNodeInfos(
VariablesViewState* viewState, void* parent, VariablesViewState* viewState,
void* parent,
TreeTablePath& path); TreeTablePath& path);
void _CopyVariableValueToClipboard(); void _CopyVariableValueToClipboard();
@@ -1,4 +1,5 @@
/* /*
* Copyright 2014, Rene Gollent, [email protected].
* Copyright 2009, Ingo Weinhold, [email protected]. * Copyright 2009, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
@@ -18,14 +19,15 @@ bool_value_string(BoolValue* value)
void void
TableCellBoolRenderer::RenderValue(Value* _value, BRect rect, BView* targetView) TableCellBoolRenderer::RenderValue(Value* _value, bool valueChanged,
BRect rect, BView* targetView)
{ {
BoolValue* value = dynamic_cast<BoolValue*>(_value); BoolValue* value = dynamic_cast<BoolValue*>(_value);
if (value == NULL) if (value == NULL)
return; return;
TableCellValueRendererUtils::DrawString(targetView, rect, TableCellValueRendererUtils::DrawString(targetView, rect,
bool_value_string(value), B_ALIGN_RIGHT, true); bool_value_string(value), valueChanged, B_ALIGN_RIGHT, true);
} }
@@ -1,4 +1,5 @@
/* /*
* Copyright 2014, Rene Gollent, [email protected].
* Copyright 2009, Ingo Weinhold, [email protected]. * Copyright 2009, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
@@ -13,8 +14,8 @@
class TableCellBoolRenderer : public TableCellValueRenderer { class TableCellBoolRenderer : public TableCellValueRenderer {
public: public:
virtual void RenderValue(Value* value, BRect rect, virtual void RenderValue(Value* value, bool valueChanged,
BView* targetView); BRect rect, BView* targetView);
virtual float PreferredValueWidth(Value* value, virtual float PreferredValueWidth(Value* value,
BView* targetView); BView* targetView);
}; };
@@ -1,4 +1,5 @@
/* /*
* Copyright 2014, Rene Gollent, [email protected].
* Copyright 2009, Ingo Weinhold, [email protected]. * Copyright 2009, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
@@ -19,8 +20,8 @@ TableCellEnumerationRenderer::TableCellEnumerationRenderer(Config* config)
void void
TableCellEnumerationRenderer::RenderValue(Value* _value, BRect rect, TableCellEnumerationRenderer::RenderValue(Value* _value, bool valueChanged,
BView* targetView) BRect rect, BView* targetView)
{ {
Config* config = GetConfig(); Config* config = GetConfig();
if (config != NULL && config->IntegerFormat() == INTEGER_FORMAT_DEFAULT) { if (config != NULL && config->IntegerFormat() == INTEGER_FORMAT_DEFAULT) {
@@ -31,12 +32,13 @@ TableCellEnumerationRenderer::RenderValue(Value* _value, BRect rect,
if (EnumeratorValue* enumValue if (EnumeratorValue* enumValue
= value->GetType()->ValueFor(value->GetValue())) { = value->GetType()->ValueFor(value->GetValue())) {
TableCellValueRendererUtils::DrawString(targetView, rect, TableCellValueRendererUtils::DrawString(targetView, rect,
enumValue->Name(), B_ALIGN_RIGHT, true); enumValue->Name(), valueChanged, B_ALIGN_RIGHT, true);
return; return;
} }
} }
TableCellIntegerRenderer::RenderValue(_value, rect, targetView); TableCellIntegerRenderer::RenderValue(_value, valueChanged, rect,
targetView);
} }
@@ -1,4 +1,5 @@
/* /*
* Copyright 2014, Rene Gollent, [email protected].
* Copyright 2009, Ingo Weinhold, [email protected]. * Copyright 2009, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
@@ -15,8 +16,8 @@ class TableCellEnumerationRenderer : public TableCellIntegerRenderer {
public: public:
TableCellEnumerationRenderer(Config* config); TableCellEnumerationRenderer(Config* config);
virtual void RenderValue(Value* value, BRect rect, virtual void RenderValue(Value* value, bool valueChanged,
BView* targetView); BRect rect, BView* targetView);
virtual float PreferredValueWidth(Value* value, virtual float PreferredValueWidth(Value* value,
BView* targetView); BView* targetView);
}; };
@@ -1,4 +1,5 @@
/* /*
* Copyright 2014, Rene Gollent, [email protected].
* Copyright 2009, Ingo Weinhold, [email protected]. * Copyright 2009, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
@@ -13,7 +14,8 @@
void void
TableCellFloatRenderer::RenderValue(Value* _value, BRect rect, BView* targetView) TableCellFloatRenderer::RenderValue(Value* _value, bool valueChanged,
BRect rect, BView* targetView)
{ {
FloatValue* value = dynamic_cast<FloatValue*>(_value); FloatValue* value = dynamic_cast<FloatValue*>(_value);
if (value == NULL) if (value == NULL)
@@ -23,7 +25,7 @@ TableCellFloatRenderer::RenderValue(Value* _value, BRect rect, BView* targetView
snprintf(buffer, sizeof(buffer), "%g", value->GetValue()); snprintf(buffer, sizeof(buffer), "%g", value->GetValue());
TableCellValueRendererUtils::DrawString(targetView, rect, buffer, TableCellValueRendererUtils::DrawString(targetView, rect, buffer,
B_ALIGN_RIGHT, true); valueChanged, B_ALIGN_RIGHT, true);
} }
@@ -1,4 +1,5 @@
/* /*
* Copyright 2014, Rene Gollent, [email protected].
* Copyright 2009, Ingo Weinhold, [email protected]. * Copyright 2009, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
@@ -13,8 +14,8 @@
class TableCellFloatRenderer : public TableCellValueRenderer { class TableCellFloatRenderer : public TableCellValueRenderer {
public: public:
virtual void RenderValue(Value* value, BRect rect, virtual void RenderValue(Value* value, bool valueChanged,
BView* targetView); BRect rect, BView* targetView);
virtual float PreferredValueWidth(Value* value, virtual float PreferredValueWidth(Value* value,
BView* targetView); BView* targetView);
}; };
@@ -1,4 +1,5 @@
/* /*
* Copyright 2014, Rene Gollent, [email protected].
* Copyright 2009, Ingo Weinhold, [email protected]. * Copyright 2009, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
@@ -41,8 +42,8 @@ TableCellIntegerRenderer::GetSettings() const
void void
TableCellIntegerRenderer::RenderValue(Value* _value, BRect rect, TableCellIntegerRenderer::RenderValue(Value* _value, bool valueChanged,
BView* targetView) BRect rect, BView* targetView)
{ {
IntegerValue* value = dynamic_cast<IntegerValue*>(_value); IntegerValue* value = dynamic_cast<IntegerValue*>(_value);
if (value == NULL) if (value == NULL)
@@ -59,7 +60,7 @@ TableCellIntegerRenderer::RenderValue(Value* _value, BRect rect,
// render // render
TableCellValueRendererUtils::DrawString(targetView, rect, buffer, TableCellValueRendererUtils::DrawString(targetView, rect, buffer,
B_ALIGN_RIGHT, true); valueChanged, B_ALIGN_RIGHT, true);
} }
@@ -1,4 +1,5 @@
/* /*
* Copyright 2014, Rene Gollent, [email protected].
* Copyright 2009, Ingo Weinhold, [email protected]. * Copyright 2009, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
@@ -25,8 +26,8 @@ public:
virtual Settings* GetSettings() const; virtual Settings* GetSettings() const;
virtual void RenderValue(Value* value, BRect rect, virtual void RenderValue(Value* value, bool valueChanged,
BView* targetView); BRect rect, BView* targetView);
virtual float PreferredValueWidth(Value* value, virtual float PreferredValueWidth(Value* value,
BView* targetView); BView* targetView);
@@ -1,4 +1,5 @@
/* /*
* Copyright 2014, Rene Gollent, [email protected].
* Copyright 2009, Ingo Weinhold, [email protected]. * Copyright 2009, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
@@ -15,8 +16,8 @@
void void
TableCellStringRenderer::RenderValue(Value* value, BRect rect, TableCellStringRenderer::RenderValue(Value* value, bool valueChanged,
BView* targetView) BRect rect, BView* targetView)
{ {
BString string = "\""; BString string = "\"";
BString tempString; BString tempString;
@@ -64,7 +65,7 @@ TableCellStringRenderer::RenderValue(Value* value, BRect rect,
string += "\""; string += "\"";
TableCellValueRendererUtils::DrawString(targetView, rect, string, TableCellValueRendererUtils::DrawString(targetView, rect, string,
B_ALIGN_RIGHT, true); valueChanged, B_ALIGN_RIGHT, true);
} }
@@ -1,4 +1,5 @@
/* /*
* Copyright 2014, Rene Gollent, [email protected].
* Copyright 2009, Ingo Weinhold, [email protected]. * Copyright 2009, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
@@ -13,8 +14,8 @@
class TableCellStringRenderer : public TableCellValueRenderer { class TableCellStringRenderer : public TableCellValueRenderer {
public: public:
virtual void RenderValue(Value* value, BRect rect, virtual void RenderValue(Value* value, bool valueChanged,
BView* targetView); BRect rect, BView* targetView);
virtual float PreferredValueWidth(Value* value, virtual float PreferredValueWidth(Value* value,
BView* targetView); BView* targetView);
}; };
@@ -1,4 +1,5 @@
/* /*
* Copyright 2014, Rene Gollent, [email protected].
* Copyright 2009, Ingo Weinhold, [email protected]. * Copyright 2009, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
@@ -23,8 +24,8 @@ public:
virtual Settings* GetSettings() const; virtual Settings* GetSettings() const;
// returns NULL, if no settings // returns NULL, if no settings
virtual void RenderValue(Value* value, BRect rect, virtual void RenderValue(Value* value, bool valueChanged,
BView* targetView) = 0; BRect rect, BView* targetView) = 0;
virtual float PreferredValueWidth(Value* value, virtual float PreferredValueWidth(Value* value,
BView* targetView) = 0; BView* targetView) = 0;
}; };
@@ -16,7 +16,8 @@ static const float kTextMargin = 8;
/*static*/ void /*static*/ void
TableCellValueRendererUtils::DrawString(BView* view, BRect rect, TableCellValueRendererUtils::DrawString(BView* view, BRect rect,
const char* string, enum alignment alignment, bool truncate) const char* string, bool valueChanged, enum alignment alignment,
bool truncate)
{ {
// get font height info // get font height info
font_height fontHeight; font_height fontHeight;
@@ -56,7 +57,15 @@ TableCellValueRendererUtils::DrawString(BView* view, BRect rect,
// TODO: This is the computation BColumnListView (respectively // TODO: This is the computation BColumnListView (respectively
// BTitledColumn) is using, which I find somewhat weird. // BTitledColumn) is using, which I find somewhat weird.
if (valueChanged) {
view->PushState();
view->SetHighColor((rgb_color){255, 0, 0, 255});
}
view->DrawString(string, BPoint(x, y)); view->DrawString(string, BPoint(x, y));
if (valueChanged)
view->PopState();
} }
@@ -17,6 +17,7 @@ class TableCellValueRendererUtils {
public: public:
static void DrawString(BView* view, BRect rect, static void DrawString(BView* view, BRect rect,
const char* string, const char* string,
bool valueChanged,
enum alignment alignment, enum alignment alignment,
bool truncate = false); bool truncate = false);
static float PreferredStringWidth(BView* view, static float PreferredStringWidth(BView* view,