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:42:59 -04:00
parent f40556afab
commit b6c4fc962c
15 changed files with 129 additions and 38 deletions

View File

@ -108,13 +108,15 @@ public:
fNodeChild(nodeChild),
fVariable(variable),
fValue(NULL),
fPreviousValue(),
fValueHandler(NULL),
fTableCellRenderer(NULL),
fLastRendererSettings(),
fCastedType(NULL),
fComponentPath(NULL),
fIsPresentationNode(isPresentationNode),
fHidden(false)
fHidden(false),
fValueChanged(false)
{
fNodeChild->AcquireReference();
}
@ -202,6 +204,18 @@ public:
if (fValue != NULL)
fValue->AcquireReference();
_CompareValues();
}
const BVariant& PreviousValue() const
{
return fPreviousValue;
}
void SetPreviousValue(const BVariant& value)
{
fPreviousValue = value;
}
Type* GetCastedType() const
@ -288,6 +302,11 @@ public:
fHidden = hidden;
}
bool ValueChanged() const
{
return fValueChanged;
}
int32 CountChildren() const
{
return fChildren.CountItems();
@ -332,11 +351,24 @@ public:
private:
typedef BObjectList<ModelNode> ChildList;
private:
void _CompareValues()
{
if (fValue == NULL)
fValueChanged = false;
else {
BVariant newValue;
fValue->ToVariant(newValue);
fValueChanged = (fPreviousValue != newValue);
}
}
private:
ModelNode* fParent;
ValueNodeChild* fNodeChild;
Variable* fVariable;
Value* fValue;
BVariant fPreviousValue;
ValueHandler* fValueHandler;
TableCellValueRenderer* fTableCellRenderer;
BMessage fLastRendererSettings;
@ -345,6 +377,7 @@ private:
TypeComponentPath* fComponentPath;
bool fIsPresentationNode;
bool fHidden;
bool fValueChanged;
public:
ModelNode* fNext;
@ -373,8 +406,8 @@ protected:
ModelNode* node = dynamic_cast<ModelNode*>(value.ToReferenceable());
if (node != NULL && node->GetValue() != NULL
&& node->TableCellRenderer() != NULL) {
node->TableCellRenderer()->RenderValue(node->GetValue(), rect,
targetView);
node->TableCellRenderer()->RenderValue(node->GetValue(),
node->ValueChanged(), rect, targetView);
return;
}
} else if (value.Type() == B_STRING_TYPE) {
@ -1102,6 +1135,8 @@ VariablesView::VariableTableModel::ValueNodeValueChanged(ValueNode* valueNode)
settings->RestoreValues(modelNode->GetLastRendererSettings());
}
// notify table model listeners
NotifyNodeChanged(modelNode);
}
@ -2168,6 +2203,14 @@ VariablesView::_SaveViewState() const
return;
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
VariablesViewState* viewState = new(std::nothrow) VariablesViewState;
if (viewState == NULL)
@ -2177,13 +2220,14 @@ VariablesView::_SaveViewState() const
if (viewState->Init() != B_OK)
return;
viewState->SetValues(values);
// populate it
TreeTablePath path;
if (_AddViewStateDescendentNodeInfos(viewState, fVariableTableModel->Root(),
path) != B_OK) {
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);
@ -2243,11 +2287,23 @@ VariablesView::_AddViewStateDescendentNodeInfos(VariablesViewState* viewState,
nodeInfo.SetRendererSettings(settings->Message());
}
status_t error = viewState->SetNodeInfo(node->GetVariable()->ID(),
node->GetPath(), nodeInfo);
ObjectID* id = node->GetVariable()->ID();
TypeComponentPath* componentPath = node->GetPath();
status_t error = viewState->SetNodeInfo(id, componentPath, nodeInfo);
if (error != B_OK)
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
error = _AddViewStateDescendentNodeInfos(viewState, node, path);
if (error != B_OK)
@ -2271,8 +2327,10 @@ VariablesView::_ApplyViewStateDescendentNodeInfos(VariablesViewState* viewState,
return B_NO_MEMORY;
// apply the node's info, if any
ObjectID* objectID = node->GetVariable()->ID();
TypeComponentPath* componentPath = node->GetPath();
const VariablesViewNodeInfo* nodeInfo = viewState->GetNodeInfo(
node->GetVariable()->ID(), node->GetPath());
objectID, componentPath);
if (nodeInfo != NULL) {
// NB: if the node info indicates that the node in question
// was being cast to a different type, this *must* be applied
@ -2295,6 +2353,12 @@ VariablesView::_ApplyViewStateDescendentNodeInfos(VariablesViewState* viewState,
fVariableTable->SetNodeExpanded(path, nodeInfo->IsNodeExpanded());
BVariant previousValue;
if (viewState->Values()->GetValue(objectID, componentPath,
previousValue)) {
node->SetPreviousValue(previousValue);
}
// recurse
status_t error = _ApplyViewStateDescendentNodeInfos(viewState, node,
path);

View File

@ -16,6 +16,7 @@ class ActionMenuItem;
class CpuState;
class SettingsMenu;
class StackFrame;
class StackFrameValues;
class Thread;
class Type;
class TypeComponentPath;
@ -81,10 +82,12 @@ private:
void _SaveViewState() const;
void _RestoreViewState();
status_t _AddViewStateDescendentNodeInfos(
VariablesViewState* viewState, void* parent,
VariablesViewState* viewState,
void* parent,
TreeTablePath& path) const;
status_t _ApplyViewStateDescendentNodeInfos(
VariablesViewState* viewState, void* parent,
VariablesViewState* viewState,
void* parent,
TreeTablePath& path);
void _CopyVariableValueToClipboard();

View File

@ -1,4 +1,5 @@
/*
* Copyright 2014, Rene Gollent, rene@gollent.com.
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
@ -18,14 +19,15 @@ bool_value_string(BoolValue* value)
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);
if (value == NULL)
return;
TableCellValueRendererUtils::DrawString(targetView, rect,
bool_value_string(value), B_ALIGN_RIGHT, true);
bool_value_string(value), valueChanged, B_ALIGN_RIGHT, true);
}

View File

@ -1,4 +1,5 @@
/*
* Copyright 2014, Rene Gollent, rene@gollent.com.
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
@ -13,8 +14,8 @@
class TableCellBoolRenderer : public TableCellValueRenderer {
public:
virtual void RenderValue(Value* value, BRect rect,
BView* targetView);
virtual void RenderValue(Value* value, bool valueChanged,
BRect rect, BView* targetView);
virtual float PreferredValueWidth(Value* value,
BView* targetView);
};

View File

@ -1,4 +1,5 @@
/*
* Copyright 2014, Rene Gollent, rene@gollent.com.
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
@ -19,8 +20,8 @@ TableCellEnumerationRenderer::TableCellEnumerationRenderer(Config* config)
void
TableCellEnumerationRenderer::RenderValue(Value* _value, BRect rect,
BView* targetView)
TableCellEnumerationRenderer::RenderValue(Value* _value, bool valueChanged,
BRect rect, BView* targetView)
{
Config* config = GetConfig();
if (config != NULL && config->IntegerFormat() == INTEGER_FORMAT_DEFAULT) {
@ -31,12 +32,13 @@ TableCellEnumerationRenderer::RenderValue(Value* _value, BRect rect,
if (EnumeratorValue* enumValue
= value->GetType()->ValueFor(value->GetValue())) {
TableCellValueRendererUtils::DrawString(targetView, rect,
enumValue->Name(), B_ALIGN_RIGHT, true);
enumValue->Name(), valueChanged, B_ALIGN_RIGHT, true);
return;
}
}
TableCellIntegerRenderer::RenderValue(_value, rect, targetView);
TableCellIntegerRenderer::RenderValue(_value, valueChanged, rect,
targetView);
}

View File

@ -1,4 +1,5 @@
/*
* Copyright 2014, Rene Gollent, rene@gollent.com.
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
@ -15,8 +16,8 @@ class TableCellEnumerationRenderer : public TableCellIntegerRenderer {
public:
TableCellEnumerationRenderer(Config* config);
virtual void RenderValue(Value* value, BRect rect,
BView* targetView);
virtual void RenderValue(Value* value, bool valueChanged,
BRect rect, BView* targetView);
virtual float PreferredValueWidth(Value* value,
BView* targetView);
};

View File

@ -1,4 +1,5 @@
/*
* Copyright 2014, Rene Gollent, rene@gollent.com.
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
@ -13,7 +14,8 @@
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);
if (value == NULL)
@ -23,7 +25,7 @@ TableCellFloatRenderer::RenderValue(Value* _value, BRect rect, BView* targetView
snprintf(buffer, sizeof(buffer), "%g", value->GetValue());
TableCellValueRendererUtils::DrawString(targetView, rect, buffer,
B_ALIGN_RIGHT, true);
valueChanged, B_ALIGN_RIGHT, true);
}

View File

@ -1,4 +1,5 @@
/*
* Copyright 2014, Rene Gollent, rene@gollent.com.
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
@ -13,8 +14,8 @@
class TableCellFloatRenderer : public TableCellValueRenderer {
public:
virtual void RenderValue(Value* value, BRect rect,
BView* targetView);
virtual void RenderValue(Value* value, bool valueChanged,
BRect rect, BView* targetView);
virtual float PreferredValueWidth(Value* value,
BView* targetView);
};

View File

@ -1,4 +1,5 @@
/*
* Copyright 2014, Rene Gollent, rene@gollent.com.
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
@ -41,8 +42,8 @@ TableCellIntegerRenderer::GetSettings() const
void
TableCellIntegerRenderer::RenderValue(Value* _value, BRect rect,
BView* targetView)
TableCellIntegerRenderer::RenderValue(Value* _value, bool valueChanged,
BRect rect, BView* targetView)
{
IntegerValue* value = dynamic_cast<IntegerValue*>(_value);
if (value == NULL)
@ -59,7 +60,7 @@ TableCellIntegerRenderer::RenderValue(Value* _value, BRect rect,
// render
TableCellValueRendererUtils::DrawString(targetView, rect, buffer,
B_ALIGN_RIGHT, true);
valueChanged, B_ALIGN_RIGHT, true);
}

View File

@ -1,4 +1,5 @@
/*
* Copyright 2014, Rene Gollent, rene@gollent.com.
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
@ -25,8 +26,8 @@ public:
virtual Settings* GetSettings() const;
virtual void RenderValue(Value* value, BRect rect,
BView* targetView);
virtual void RenderValue(Value* value, bool valueChanged,
BRect rect, BView* targetView);
virtual float PreferredValueWidth(Value* value,
BView* targetView);

View File

@ -1,4 +1,5 @@
/*
* Copyright 2014, Rene Gollent, rene@gollent.com.
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
@ -15,8 +16,8 @@
void
TableCellStringRenderer::RenderValue(Value* value, BRect rect,
BView* targetView)
TableCellStringRenderer::RenderValue(Value* value, bool valueChanged,
BRect rect, BView* targetView)
{
BString string = "\"";
BString tempString;
@ -64,7 +65,7 @@ TableCellStringRenderer::RenderValue(Value* value, BRect rect,
string += "\"";
TableCellValueRendererUtils::DrawString(targetView, rect, string,
B_ALIGN_RIGHT, true);
valueChanged, B_ALIGN_RIGHT, true);
}

View File

@ -1,4 +1,5 @@
/*
* Copyright 2014, Rene Gollent, rene@gollent.com.
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
@ -13,8 +14,8 @@
class TableCellStringRenderer : public TableCellValueRenderer {
public:
virtual void RenderValue(Value* value, BRect rect,
BView* targetView);
virtual void RenderValue(Value* value, bool valueChanged,
BRect rect, BView* targetView);
virtual float PreferredValueWidth(Value* value,
BView* targetView);
};

View File

@ -1,4 +1,5 @@
/*
* Copyright 2014, Rene Gollent, rene@gollent.com.
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
@ -23,8 +24,8 @@ public:
virtual Settings* GetSettings() const;
// returns NULL, if no settings
virtual void RenderValue(Value* value, BRect rect,
BView* targetView) = 0;
virtual void RenderValue(Value* value, bool valueChanged,
BRect rect, BView* targetView) = 0;
virtual float PreferredValueWidth(Value* value,
BView* targetView) = 0;
};

View File

@ -16,7 +16,8 @@ static const float kTextMargin = 8;
/*static*/ void
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
font_height fontHeight;
@ -56,7 +57,15 @@ TableCellValueRendererUtils::DrawString(BView* view, BRect rect,
// TODO: This is the computation BColumnListView (respectively
// 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));
if (valueChanged)
view->PopState();
}

View File

@ -17,6 +17,7 @@ class TableCellValueRendererUtils {
public:
static void DrawString(BView* view, BRect rect,
const char* string,
bool valueChanged,
enum alignment alignment,
bool truncate = false);
static float PreferredStringWidth(BView* view,