Browse Source

Object graph visualizer - user can expand/collapse nodes.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4275 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Martin Koníček 16 years ago
parent
commit
bce5fe49da
  1. 13
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Debugger.AddIn.csproj
  2. 1
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Drawing/NodeControl.xaml
  3. 185
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Drawing/NodeControl.xaml.cs
  4. 38
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ExpandedNodes.cs
  5. 7
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedGraph.cs
  6. 47
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedNode.cs
  7. 22
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedNodeProperty.cs
  8. 25
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedPropertyEventArgs.cs
  9. 17
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeLayouter.cs
  10. 10
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/ObjectGraphBuilder.cs
  11. 4
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/ObjectProperty.cs
  12. 39
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraphVisualizerViewContent.cs
  13. 12
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/VisualizerWPFControl.xaml
  14. 33
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/VisualizerWPFControl.xaml.cs
  15. 33
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/VisualizerWPFWindow.xaml.cs
  16. 92
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/VisualizerWinFormsControl.Designer.cs
  17. 84
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/VisualizerWinFormsControl.cs

13
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Debugger.AddIn.csproj

@ -170,13 +170,17 @@
<Compile Include="Src\Visualizers\Graph\DebuggerVisualizerException.cs" /> <Compile Include="Src\Visualizers\Graph\DebuggerVisualizerException.cs" />
<Compile Include="Src\Visualizers\Graph\Drawing\CanvasLocationAdapter.cs" /> <Compile Include="Src\Visualizers\Graph\Drawing\CanvasLocationAdapter.cs" />
<Compile Include="Src\Visualizers\Graph\Drawing\GraphDrawer.cs" /> <Compile Include="Src\Visualizers\Graph\Drawing\GraphDrawer.cs" />
<Compile Include="Src\Visualizers\Graph\Drawing\NodeControl.xaml.cs" /> <Compile Include="Src\Visualizers\Graph\Drawing\NodeControl.xaml.cs">
<DependentUpon>NodeControl.xaml</DependentUpon>
</Compile>
<Compile Include="Src\Visualizers\Graph\ExpandedNodes.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\GraphDiff.cs" /> <Compile Include="Src\Visualizers\Graph\Layout\GraphDiff.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\GraphMatcher.cs" /> <Compile Include="Src\Visualizers\Graph\Layout\GraphMatcher.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\PositionedEdge.cs" /> <Compile Include="Src\Visualizers\Graph\Layout\PositionedEdge.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\PositionedGraph.cs" /> <Compile Include="Src\Visualizers\Graph\Layout\PositionedGraph.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\PositionedNode.cs" /> <Compile Include="Src\Visualizers\Graph\Layout\PositionedNode.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\PositionedNodeProperty.cs" /> <Compile Include="Src\Visualizers\Graph\Layout\PositionedNodeProperty.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\PositionedPropertyEventArgs.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\Tree\BoxDotFormatter.cs" /> <Compile Include="Src\Visualizers\Graph\Layout\Tree\BoxDotFormatter.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\Tree\DotFormatter.cs" /> <Compile Include="Src\Visualizers\Graph\Layout\Tree\DotFormatter.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\Tree\IdGenerator.cs" /> <Compile Include="Src\Visualizers\Graph\Layout\Tree\IdGenerator.cs" />
@ -190,7 +194,6 @@
<Compile Include="Src\Visualizers\Graph\Layout\Tree\TreeNode.cs" /> <Compile Include="Src\Visualizers\Graph\Layout\Tree\TreeNode.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\Tree\TreeNodeLR.cs" /> <Compile Include="Src\Visualizers\Graph\Layout\Tree\TreeNodeLR.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\Tree\TreeNodeTB.cs" /> <Compile Include="Src\Visualizers\Graph\Layout\Tree\TreeNodeTB.cs" />
<Compile Include="Src\Visualizers\Graph\ObjectGraphVisualizerViewContent.cs" />
<Compile Include="Src\Visualizers\Graph\ObjectGraph\NamedEdge.cs" /> <Compile Include="Src\Visualizers\Graph\ObjectGraph\NamedEdge.cs" />
<Compile Include="Src\Visualizers\Graph\ObjectGraph\ObjectEdge.cs" /> <Compile Include="Src\Visualizers\Graph\ObjectGraph\ObjectEdge.cs" />
<Compile Include="Src\Visualizers\Graph\ObjectGraph\ObjectGraph.cs" /> <Compile Include="Src\Visualizers\Graph\ObjectGraph\ObjectGraph.cs" />
@ -202,11 +205,6 @@
<Compile Include="Src\Visualizers\Graph\Utils\DictionaryExtensions.cs" /> <Compile Include="Src\Visualizers\Graph\Utils\DictionaryExtensions.cs" />
<Compile Include="Src\Visualizers\Graph\Utils\Lookup.cs" /> <Compile Include="Src\Visualizers\Graph\Utils\Lookup.cs" />
<Compile Include="Src\Visualizers\Graph\Utils\LookupValueCollection.cs" /> <Compile Include="Src\Visualizers\Graph\Utils\LookupValueCollection.cs" />
<Compile Include="Src\Visualizers\Graph\VisualizerWinFormsControl.cs" />
<Compile Include="Src\Visualizers\Graph\VisualizerWinFormsControl.Designer.cs" />
<Compile Include="Src\Visualizers\Graph\VisualizerWPFControl.xaml.cs">
<DependentUpon>VisualizerWPFControl.xaml</DependentUpon>
</Compile>
<Compile Include="Src\Visualizers\Graph\VisualizerWPFWindow.xaml.cs"> <Compile Include="Src\Visualizers\Graph\VisualizerWPFWindow.xaml.cs">
<DependentUpon>VisualizerWPFWindow.xaml</DependentUpon> <DependentUpon>VisualizerWPFWindow.xaml</DependentUpon>
</Compile> </Compile>
@ -300,7 +298,6 @@
<Folder Include="Src\Visualizers\Graph\Utils" /> <Folder Include="Src\Visualizers\Graph\Utils" />
<Folder Include="Src\Visualizers\PresentationBindings" /> <Folder Include="Src\Visualizers\PresentationBindings" />
<Page Include="Src\Visualizers\Graph\Drawing\NodeControl.xaml" /> <Page Include="Src\Visualizers\Graph\Drawing\NodeControl.xaml" />
<Page Include="Src\Visualizers\Graph\VisualizerWPFControl.xaml" />
<Page Include="Src\Visualizers\Graph\VisualizerWPFWindow.xaml" /> <Page Include="Src\Visualizers\Graph\VisualizerWPFWindow.xaml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

1
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Drawing/NodeControl.xaml

@ -16,6 +16,7 @@
<Grid.RowDefinitions> <Grid.RowDefinitions>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>

185
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Drawing/NodeControl.xaml.cs

@ -4,6 +4,7 @@
// <owner name="Martin Koníček" email="martin.konicek@gmail.com"/> // <owner name="Martin Koníček" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version> // <version>$Revision$</version>
// </file> // </file>
using Debugger.AddIn.Visualizers.Graph.Layout;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
@ -20,59 +21,133 @@ using Debugger.AddIn.Visualizers.Graph;
namespace Debugger.AddIn.Visualizers.Graph.Drawing namespace Debugger.AddIn.Visualizers.Graph.Drawing
{ {
/// <summary> /// <summary>
/// UserControl used to display ObjectNode. /// UserControl used to display Positione.
/// </summary> /// </summary>
public partial class NodeControl : UserControl public partial class NodeControl : UserControl
{ {
public NodeControl() /// <summary>
{ /// Creates new NodeControl displaying PositionedNode.
InitializeComponent(); /// </summary>
} /// <param name="graphNode">PositionedNode displayed by the control.</param>
public NodeControl(PositionedNode graphNode) : this()
private ObjectNode node; {
/// <summary> //this.initializeWithGraphNode(graphNode);
/// ObjectNode that this control displays. this.GraphNode = graphNode;
/// </summary> }
public ObjectNode GraphNode
{ public NodeControl()
get {
{ InitializeComponent();
return node; }
}
set public event EventHandler<PositionedPropertyEventArgs> Expanded;
{ public event EventHandler<PositionedPropertyEventArgs> Collapsed;
node = value;
int row = 0; private PositionedNode node;
// dynamically create TextBlocks and insert them to the 2-column propertyGrid /// <summary>
foreach (var property in node.Properties) /// ObjectNode that this control displays.
{ /// </summary>
propertyGrid.RowDefinitions.Add(new RowDefinition()); public PositionedNode GraphNode
{
TextBlock txtName = createTextBlock(property.Name); get
propertyGrid.Children.Add(txtName); {
Grid.SetRow(txtName, row); return node;
Grid.SetColumn(txtName, 0); }
private set
TextBlock txtValue = createTextBlock(property.Value); {
propertyGrid.Children.Add(txtValue); this.node = value;
Grid.SetRow(txtValue, row); }
Grid.SetColumn(txtValue, 1); }
row++; public void AddProperty(PositionedNodeProperty property)
} {
} int nRow = propertyGrid.RowDefinitions.Count;
}
var row = new RowDefinition();
/// <summary> propertyGrid.RowDefinitions.Add(row);
/// Creates TextBlock with given text.
/// </summary> if (!property.IsAtomic)
private TextBlock createTextBlock(string text) {
{ Button btnExpandCollapse = new Button();
TextBlock newTextblock = new TextBlock(); btnExpandCollapse.Tag = property;
newTextblock.Text = text; btnExpandCollapse.Content = property.IsExpanded ? "-" : "+";
newTextblock.Padding = new Thickness(4); btnExpandCollapse.Width = 20;
return newTextblock; propertyGrid.Children.Add(btnExpandCollapse);
} Grid.SetRow(btnExpandCollapse, nRow);
} Grid.SetColumn(btnExpandCollapse, 0);
btnExpandCollapse.Click += new RoutedEventHandler(btnExpandCollapse_Click);
}
TextBlock txtName = createTextBlock(property.Name);
propertyGrid.Children.Add(txtName);
Grid.SetRow(txtName, nRow);
Grid.SetColumn(txtName, 1);
TextBlock txtValue = createTextBlock(property.Value);
propertyGrid.Children.Add(txtValue);
Grid.SetRow(txtValue, nRow);
Grid.SetColumn(txtValue, 2);
}
/*public void Measure()
{
this.Measure();
int nRow = 0;
// dynamically create TextBlocks and insert them to the 2-column propertyGrid
foreach (var property in node.Properties)
{
nRow++;
}
}*/
void btnExpandCollapse_Click(object sender, RoutedEventArgs e)
{
Button buttonClicked = ((Button)sender);
var property = (PositionedNodeProperty)buttonClicked.Tag;
property.IsExpanded = !property.IsExpanded;
buttonClicked.Content = property.IsExpanded ? "-" : "+";
if (property.IsExpanded)
{
OnPropertyExpanded(property);
}
else
{
OnPropertyCollapsed(property);
}
}
/// <summary>
/// Creates TextBlock with given text.
/// </summary>
private TextBlock createTextBlock(string text)
{
TextBlock newTextblock = new TextBlock();
newTextblock.Text = text;
newTextblock.Padding = new Thickness(4);
return newTextblock;
}
#region event helpers
protected virtual void OnPropertyExpanded(PositionedNodeProperty property)
{
if (this.Expanded != null)
{
this.Expanded(this, new PositionedPropertyEventArgs(property));
}
}
protected virtual void OnPropertyCollapsed(PositionedNodeProperty property)
{
if (this.Collapsed != null)
{
this.Collapsed(this, new PositionedPropertyEventArgs(property));
}
}
#endregion
}
} }

38
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ExpandedNodes.cs

@ -0,0 +1,38 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Martin Koníček" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
namespace Debugger.AddIn.Visualizers.Graph
{
/// <summary>
/// Remembers which expressions the user has expanded.
/// </summary>
public class ExpandedNodes
{
private Dictionary<string, bool> expandedNodes = new Dictionary<string, bool>();
public ExpandedNodes()
{
}
public bool IsExpanded(string expression)
{
return expandedNodes.ContainsKey(expression) && (expandedNodes[expression] == true);
}
public void Expand(string expression)
{
expandedNodes[expression] = true;
}
public void Collapse(string expression)
{
expandedNodes[expression] = false;
}
}
}

7
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedGraph.cs

@ -16,7 +16,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
/// </summary> /// </summary>
public class PositionedGraph public class PositionedGraph
{ {
internal List<PositionedNode> nodes = new List<PositionedNode>(); private List<PositionedNode> nodes = new List<PositionedNode>();
public System.Windows.Rect BoundingRect public System.Windows.Rect BoundingRect
{ {
@ -39,6 +39,11 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
get { return nodes; } get { return nodes; }
} }
internal void AddNode(PositionedNode node)
{
this.nodes.Add(node);
}
/// <summary> /// <summary>
/// All edges in the graph. /// All edges in the graph.
/// </summary> /// </summary>

47
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedNode.cs

@ -25,6 +25,9 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
get { return objectNode; } get { return objectNode; }
} }
public event EventHandler<PositionedPropertyEventArgs> Expanded;
public event EventHandler<PositionedPropertyEventArgs> Collapsed;
private List<PositionedNodeProperty> properties = new List<PositionedNodeProperty>(); private List<PositionedNodeProperty> properties = new List<PositionedNodeProperty>();
public List<PositionedNodeProperty> Properties public List<PositionedNodeProperty> Properties
{ {
@ -34,10 +37,13 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
} }
} }
public PositionedNodeProperty AddProperty(ObjectProperty objectProperty) public PositionedNodeProperty AddProperty(ObjectProperty objectProperty, bool isExpanded)
{ {
var newProperty = new PositionedNodeProperty(objectProperty, this); var newProperty = new PositionedNodeProperty(objectProperty, this);
newProperty.IsExpanded = isExpanded;
this.Properties.Add(newProperty); this.Properties.Add(newProperty);
this.nodeVisualControl.AddProperty(newProperty);
return newProperty; return newProperty;
} }
@ -49,8 +55,25 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
{ {
this.objectNode = objectNode; this.objectNode = objectNode;
this.nodeVisualControl = new NodeControl(); this.nodeVisualControl = new NodeControl(this); // display
this.nodeVisualControl.GraphNode = this.objectNode; // display this.nodeVisualControl.Expanded += new EventHandler<PositionedPropertyEventArgs>(NodeVisualControl_Expanded);
this.nodeVisualControl.Collapsed += new EventHandler<PositionedPropertyEventArgs>(NodeVisualControl_Collapsed);
}
private void NodeVisualControl_Expanded(object sender, PositionedPropertyEventArgs e)
{
// propagage event
OnPropertyExpanded(this, e);
}
private void NodeVisualControl_Collapsed(object sender, PositionedPropertyEventArgs e)
{
// propagate event
OnPropertyCollapsed(this, e);
}
public void Measure()
{
this.nodeVisualControl.Measure(new Size(500, 500)); this.nodeVisualControl.Measure(new Size(500, 500));
} }
@ -100,5 +123,23 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
} }
} }
} }
#region event helpers
protected virtual void OnPropertyExpanded(object sender, PositionedPropertyEventArgs propertyArgs)
{
if (this.Expanded != null)
{
this.Expanded(sender, propertyArgs);
}
}
protected virtual void OnPropertyCollapsed(object sender, PositionedPropertyEventArgs propertyArgs)
{
if (this.Collapsed != null)
{
this.Collapsed(sender, propertyArgs);
}
}
#endregion
} }
} }

22
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedNodeProperty.cs

@ -23,6 +23,8 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
this.containingNode = containingNode; this.containingNode = containingNode;
} }
public bool IsExpanded { get; set; }
private ObjectProperty objectProperty; private ObjectProperty objectProperty;
/// <summary> /// <summary>
/// Underlying <see cref="ObjectProperty"/>. /// Underlying <see cref="ObjectProperty"/>.
@ -45,5 +47,25 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
/// Edge outgoing from this property to another <see cref="PositionedNode"/>. /// Edge outgoing from this property to another <see cref="PositionedNode"/>.
/// </summary> /// </summary>
public PositionedEdge Edge { get; set; } public PositionedEdge Edge { get; set; }
/// <summary>
/// e.g. "Age"
/// </summary>
public string Name { get { return this.objectProperty.Name; } }
/// <summary>
/// e.g. "19"
/// </summary>
public string Value { get { return this.objectProperty.Value; } }
/// <summary>
/// Full Debugger expression used to obtain value of this property.
/// </summary>
public Debugger.Expressions.Expression Expression { get { return this.objectProperty.Expression; } }
/// <summary>
/// Is this property of atomic type? (int, string, etc.)
/// </summary>
public bool IsAtomic { get { return this.objectProperty.IsAtomic; } }
} }
} }

25
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedPropertyEventArgs.cs

@ -0,0 +1,25 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Martin Koníček" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
namespace Debugger.AddIn.Visualizers.Graph.Layout
{
/// <summary>
/// EventArgs carrying <see cref="PositionedNodeProperty"/>.
/// </summary>
public class PositionedPropertyEventArgs : EventArgs
{
private PositionedNodeProperty property;
public PositionedPropertyEventArgs(PositionedNodeProperty property)
{
this.property = property;
}
public PositionedNodeProperty Property { get { return this.property; } }
}
}

17
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeLayouter.cs

@ -36,7 +36,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
/// </summary> /// </summary>
/// <param name="objectGraph"></param> /// <param name="objectGraph"></param>
/// <returns></returns> /// <returns></returns>
public PositionedGraph CalculateLayout(ObjectGraph objectGraph, LayoutDirection direction) public PositionedGraph CalculateLayout(ObjectGraph objectGraph, LayoutDirection direction, ExpandedNodes expandedNodes)
{ {
layoutDirection = direction; layoutDirection = direction;
@ -44,7 +44,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
treeNodeFor = new Dictionary<ObjectNode, TreeNode>(); treeNodeFor = new Dictionary<ObjectNode, TreeNode>();
seenNodes = new Dictionary<ObjectNode, object>(); seenNodes = new Dictionary<ObjectNode, object>();
TreeNode tree = buildTreeRecursive(objectGraph.Root); TreeNode tree = buildTreeRecursive(objectGraph.Root, expandedNodes);
calculateNodePosRecursive(tree, 0, 0); calculateNodePosRecursive(tree, 0, 0);
var neatoRouter = new NeatoEdgeRouter(); var neatoRouter = new NeatoEdgeRouter();
@ -53,14 +53,14 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
return resultGraph; return resultGraph;
} }
private TreeNode buildTreeRecursive(ObjectNode objectGraphNode) private TreeNode buildTreeRecursive(ObjectNode objectGraphNode, ExpandedNodes expandedNodes)
{ {
seenNodes.Add(objectGraphNode, null); seenNodes.Add(objectGraphNode, null);
TreeNode newTreeNode = TreeNode.Create(this.layoutDirection, objectGraphNode); TreeNode newTreeNode = TreeNode.Create(this.layoutDirection, objectGraphNode);
newTreeNode.HorizontalMargin = horizNodeMargin; newTreeNode.HorizontalMargin = horizNodeMargin;
newTreeNode.VerticalMargin = vertNodeMargin; newTreeNode.VerticalMargin = vertNodeMargin;
resultGraph.nodes.Add(newTreeNode); resultGraph.AddNode(newTreeNode);
treeNodeFor[objectGraphNode] = newTreeNode; treeNodeFor[objectGraphNode] = newTreeNode;
double subtreeSize = 0; double subtreeSize = 0;
@ -78,19 +78,20 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
} }
else else
{ {
targetTreeNode = buildTreeRecursive(neighbor); targetTreeNode = buildTreeRecursive(neighbor, expandedNodes);
newEdgeIsTreeEdge = true; newEdgeIsTreeEdge = true;
subtreeSize += targetTreeNode.SubtreeSize; subtreeSize += targetTreeNode.SubtreeSize;
} }
var posNodeProperty = newTreeNode.AddProperty(property); var posNodeProperty = newTreeNode.AddProperty(property, expandedNodes.IsExpanded(property.Expression.Code));
posNodeProperty.Edge = new TreeGraphEdge { IsTreeEdge = newEdgeIsTreeEdge, Name = property.Name, Source = posNodeProperty, Target = targetTreeNode }; posNodeProperty.Edge = new TreeGraphEdge { IsTreeEdge = newEdgeIsTreeEdge, Name = property.Name, Source = posNodeProperty, Target = targetTreeNode };
} }
else else
{ {
// PositionedNodeProperty.Edge is null // property.Edge stays null
newTreeNode.AddProperty(property); newTreeNode.AddProperty(property, expandedNodes.IsExpanded(property.Expression.Code));
} }
} }
newTreeNode.Measure();
subtreeSize = Math.Max(newTreeNode.LateralSizeWithMargin, subtreeSize); subtreeSize = Math.Max(newTreeNode.LateralSizeWithMargin, subtreeSize);
newTreeNode.SubtreeSize = subtreeSize; newTreeNode.SubtreeSize = subtreeSize;

10
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/ObjectGraphBuilder.cs

@ -80,7 +80,7 @@ namespace Debugger.AddIn.Visualizers.Graph
/// </summary> /// </summary>
/// <param name="expression">Expression valid in the program being debugged (eg. variable name)</param> /// <param name="expression">Expression valid in the program being debugged (eg. variable name)</param>
/// <returns>Object graph</returns> /// <returns>Object graph</returns>
public ObjectGraph BuildGraphForExpression(string expression) public ObjectGraph BuildGraphForExpression(string expression, ExpandedNodes expandedNodes)
{ {
if (string.IsNullOrEmpty(expression)) if (string.IsNullOrEmpty(expression))
{ {
@ -92,7 +92,7 @@ namespace Debugger.AddIn.Visualizers.Graph
// empty graph for null expression // empty graph for null expression
if (!debuggerService.GetValueFromName(expression).IsNull) if (!debuggerService.GetValueFromName(expression).IsNull)
{ {
resultGraph.Root = buildGraphRecursive(debuggerService.GetValueFromName(expression).GetPermanentReference()); resultGraph.Root = buildGraphRecursive(debuggerService.GetValueFromName(expression).GetPermanentReference(), expandedNodes);
} }
return resultGraph; return resultGraph;
@ -103,7 +103,7 @@ namespace Debugger.AddIn.Visualizers.Graph
/// </summary> /// </summary>
/// <param name="rootValue">The Value for which the subgraph will be built.</param> /// <param name="rootValue">The Value for which the subgraph will be built.</param>
/// <returns>ObjectNode representing the value + all recursive members.</returns> /// <returns>ObjectNode representing the value + all recursive members.</returns>
private ObjectNode buildGraphRecursive(Value rootValue) private ObjectNode buildGraphRecursive(Value rootValue, ExpandedNodes expandedNodes)
{ {
ObjectNode thisNode = createNewNode(rootValue); ObjectNode thisNode = createNewNode(rootValue);
@ -136,7 +136,7 @@ namespace Debugger.AddIn.Visualizers.Graph
else else
{ {
ObjectNode targetNode = null; ObjectNode targetNode = null;
if (!isNull(memberExpr)) if (!isNull(memberExpr) && expandedNodes.IsExpanded(memberExpr.Code))
{ {
// for object members, edges are added // for object members, edges are added
Value memberValue = getPermanentReference(memberExpr); Value memberValue = getPermanentReference(memberExpr);
@ -146,7 +146,7 @@ namespace Debugger.AddIn.Visualizers.Graph
if (targetNode == null) if (targetNode == null)
{ {
// if no node for memberValue exists, build the subgraph for the value // if no node for memberValue exists, build the subgraph for the value
targetNode = buildGraphRecursive(memberValue); targetNode = buildGraphRecursive(memberValue, expandedNodes);
} }
} }
else else

4
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/ObjectProperty.cs

@ -19,18 +19,22 @@ namespace Debugger.AddIn.Visualizers.Graph
/// e.g. "Age" /// e.g. "Age"
/// </summary> /// </summary>
public string Name { get; set; } public string Name { get; set; }
/// <summary> /// <summary>
/// e.g. "19" /// e.g. "19"
/// </summary> /// </summary>
public string Value { get; set; } public string Value { get; set; }
/// <summary> /// <summary>
/// Expression used for obtaining this property /// Expression used for obtaining this property
/// </summary> /// </summary>
public Debugger.Expressions.Expression Expression { get; set; } public Debugger.Expressions.Expression Expression { get; set; }
/// <summary> /// <summary>
/// Node that this property points to. Can be null. Always null if <see cref="IsAtomic"/> is true. /// Node that this property points to. Can be null. Always null if <see cref="IsAtomic"/> is true.
/// </summary> /// </summary>
public ObjectNode TargetNode { get; set; } public ObjectNode TargetNode { get; set; }
/// <summary> /// <summary>
/// Is this property of atomic type? (int, string, etc.) /// Is this property of atomic type? (int, string, etc.)
/// </summary> /// </summary>

39
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraphVisualizerViewContent.cs

@ -1,39 +0,0 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Martin Koníèek" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Text;
using System.Windows.Forms;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Gui;
namespace Debugger.AddIn.Visualizers.Graph
{
/// <summary>
/// ViewContent of the visualizer.
/// </summary>
public class ObjectGraphVisualizerViewContent : AbstractViewContent
{
VisualizerWinFormsControl control = new VisualizerWinFormsControl();
/// <summary>
/// The <see cref="System.Windows.Forms.Control"/> representing the view.
/// </summary>
public override object Control
{
get
{
return control;
}
}
public ObjectGraphVisualizerViewContent()
{
this.TitleName = "Object graph visualizer";
}
}
}

12
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/VisualizerWPFControl.xaml

@ -1,12 +0,0 @@
<UserControl x:Class="Debugger.AddIn.Visualizers.Graph.VisualizerWPFControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="300" Width="300">
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Center" Padding="4">Expression:</TextBlock>
<TextBox VerticalAlignment="Center" Margin="4" Width="100"></TextBox>
<Button Padding="4" Margin="4">Inspect</Button>
</StackPanel>
<Canvas></Canvas>
</StackPanel>
</UserControl>

33
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/VisualizerWPFControl.xaml.cs

@ -1,33 +0,0 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Martin Koníček" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Debugger.AddIn.Visualizers.Graph
{
/// <summary>
/// Interaction logic for VisualizerWPFControl.xaml
/// </summary>
public partial class VisualizerWPFControl : UserControl
{
public VisualizerWPFControl()
{
InitializeComponent();
}
}
}

33
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/VisualizerWPFWindow.xaml.cs

@ -36,6 +36,11 @@ namespace Debugger.AddIn.Visualizers.Graph
private PositionedGraph currentGraph; private PositionedGraph currentGraph;
private GraphDrawer graphDrawer; private GraphDrawer graphDrawer;
/// <summary>
/// Long-lived map telling which nodes the user expanded.
/// </summary>
private ExpandedNodes expandedNodes;
public VisualizerWPFWindow() public VisualizerWPFWindow()
{ {
InitializeComponent(); InitializeComponent();
@ -52,6 +57,8 @@ namespace Debugger.AddIn.Visualizers.Graph
this.DataContext = this.layoutViewModel; this.DataContext = this.layoutViewModel;
this.graphDrawer = new GraphDrawer(this.canvas); this.graphDrawer = new GraphDrawer(this.canvas);
this.expandedNodes = new ExpandedNodes();
} }
public void debuggerService_IsProcessRunningChanged(object sender, EventArgs e) public void debuggerService_IsProcessRunningChanged(object sender, EventArgs e)
@ -90,7 +97,7 @@ namespace Debugger.AddIn.Visualizers.Graph
try try
{ {
ICSharpCode.Core.LoggingService.Debug("Debugger visualizer: Building graph for expression: " + txtExpression.Text); ICSharpCode.Core.LoggingService.Debug("Debugger visualizer: Building graph for expression: " + txtExpression.Text);
this.objectGraph = graphBuilder.BuildGraphForExpression(txtExpression.Text); this.objectGraph = graphBuilder.BuildGraphForExpression(txtExpression.Text, expandedNodes);
} }
catch(DebuggerVisualizerException ex) catch(DebuggerVisualizerException ex)
{ {
@ -115,7 +122,8 @@ namespace Debugger.AddIn.Visualizers.Graph
Layout.TreeLayouter layouter = new Layout.TreeLayouter(); Layout.TreeLayouter layouter = new Layout.TreeLayouter();
this.oldGraph = this.currentGraph; this.oldGraph = this.currentGraph;
this.currentGraph = layouter.CalculateLayout(graph, layoutViewModel.SelectedEnumValue); this.currentGraph = layouter.CalculateLayout(graph, layoutViewModel.SelectedEnumValue, this.expandedNodes);
registerExpandCollapseEvents(this.currentGraph);
var graphDiff = new GraphMatcher().MatchGraphs(oldGraph, currentGraph); var graphDiff = new GraphMatcher().MatchGraphs(oldGraph, currentGraph);
this.graphDrawer.StartAnimation(oldGraph, currentGraph, graphDiff); this.graphDrawer.StartAnimation(oldGraph, currentGraph, graphDiff);
@ -126,5 +134,26 @@ namespace Debugger.AddIn.Visualizers.Graph
{ {
MessageBox.Show(ex.Message, "Exception", MessageBoxButton.OK, MessageBoxImage.Error); MessageBox.Show(ex.Message, "Exception", MessageBoxButton.OK, MessageBoxImage.Error);
} }
void registerExpandCollapseEvents(PositionedGraph posGraph)
{
foreach (var node in posGraph.Nodes)
{
node.Expanded += new EventHandler<PositionedPropertyEventArgs>(node_Expanded);
node.Collapsed += new EventHandler<PositionedPropertyEventArgs>(node_Collapsed);
}
}
void node_Expanded(object sender, PositionedPropertyEventArgs e)
{
expandedNodes.Expand(e.Property.Expression.Code);
refreshGraph();
}
void node_Collapsed(object sender, PositionedPropertyEventArgs e)
{
expandedNodes.Collapse(e.Property.Expression.Code);
refreshGraph();
}
} }
} }

92
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/VisualizerWinFormsControl.Designer.cs generated

@ -1,92 +0,0 @@
namespace Debugger.AddIn.Visualizers.Graph
{
partial class VisualizerWinFormsControl
{
/// <summary>
/// Designer variable used to keep track of non-visual components.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Disposes resources used by the control.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing) {
if (components != null) {
components.Dispose();
}
}
base.Dispose(disposing);
}
/// <summary>
/// This method is required for Windows Forms designer support.
/// Do not change the method contents inside the source code editor. The Forms designer might
/// not be able to load this method if it was changed manually.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.txtExpression = new System.Windows.Forms.TextBox();
this.btnInspect = new System.Windows.Forms.Button();
this.lblInfo = new System.Windows.Forms.Label();
this.lblExpression = new System.Windows.Forms.Label();
this.toolTip1 = new System.Windows.Forms.ToolTip(this.components);
this.SuspendLayout();
//
// txtExpression
//
this.txtExpression.Location = new System.Drawing.Point(88, 13);
this.txtExpression.Name = "txtExpression";
this.txtExpression.Size = new System.Drawing.Size(131, 20);
this.txtExpression.TabIndex = 0;
this.toolTip1.SetToolTip(this.txtExpression, "Expression (e.g. variable name) to be inspected");
//
// btnInspect
//
this.btnInspect.Location = new System.Drawing.Point(225, 10);
this.btnInspect.Name = "btnInspect";
this.btnInspect.Size = new System.Drawing.Size(75, 23);
this.btnInspect.TabIndex = 1;
this.btnInspect.Text = "Inspect";
this.btnInspect.UseVisualStyleBackColor = true;
this.btnInspect.Click += new System.EventHandler(this.BtnInspectClick);
//
// lblInfo
//
this.lblInfo.Location = new System.Drawing.Point(11, 58);
this.lblInfo.Name = "lblInfo";
this.lblInfo.Size = new System.Drawing.Size(349, 23);
this.lblInfo.TabIndex = 2;
this.lblInfo.Text = "< Result >";
//
// lblExpression
//
this.lblExpression.Location = new System.Drawing.Point(11, 14);
this.lblExpression.Name = "lblExpression";
this.lblExpression.Size = new System.Drawing.Size(71, 23);
this.lblExpression.TabIndex = 4;
this.lblExpression.Text = "Expression:";
//
// VisualizerWinFormsControl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.lblExpression);
this.Controls.Add(this.lblInfo);
this.Controls.Add(this.btnInspect);
this.Controls.Add(this.txtExpression);
this.Name = "VisualizerWinFormsControl";
this.Size = new System.Drawing.Size(525, 426);
this.ResumeLayout(false);
this.PerformLayout();
}
private System.Windows.Forms.Button btnInspect;
private System.Windows.Forms.ToolTip toolTip1;
private System.Windows.Forms.Label lblExpression;
private System.Windows.Forms.Label lblInfo;
private System.Windows.Forms.TextBox txtExpression;
}
}

84
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/VisualizerWinFormsControl.cs

@ -1,84 +0,0 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Martin Koníèek" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Linq;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Services;
namespace Debugger.AddIn.Visualizers.Graph
{
/// <summary>
/// Windows forms control making up the object graph visualizer user interface/
/// </summary>
public partial class VisualizerWinFormsControl : UserControl
{
WindowsDebugger _debuggerService = null;
public VisualizerWinFormsControl()
{
//
// The InitializeComponent() call is required for Windows Forms designer support.
//
InitializeComponent();
_debuggerService = DebuggerService.CurrentDebugger as WindowsDebugger;
if (_debuggerService == null)
throw new ApplicationException("Only windows debugger is currently supported");
_debuggerService.IsProcessRunningChanged += new EventHandler(debuggerService_IsProcessRunningChanged);
}
public void debuggerService_IsProcessRunningChanged(object sender, EventArgs e)
{
// on step, breakpoint hit
if (!_debuggerService.IsProcessRunning)
{
refreshGraph();
}
}
void BtnInspectClick(object sender, EventArgs e)
{
refreshGraph();
}
void refreshGraph()
{
ObjectGraphBuilder graphBuilder = new ObjectGraphBuilder(_debuggerService);
ObjectGraph graph = null;
try
{
graph = graphBuilder.BuildGraphForExpression(txtExpression.Text);
}
catch(DebuggerVisualizerException ex)
{
guiHandleException(ex);
return;
}
catch(Debugger.GetValueException ex)
{
guiHandleException(ex);
return;
}
// just a simple message for checking the graph is build ok, will be replaced by graph drawing of course
//lblInfo.Text = string.Format("Done. Number of graph nodes: {0}, number of edges: {1}", graph.Nodes.Count(), graph.Edges.Count());
}
void guiHandleException(System.Exception ex)
{
lblInfo.Text = "< Result >";
MessageBox.Show(ex.Message, "Exception", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}
Loading…
Cancel
Save