Browse Source

- Grid visualizer - first prototype - shows IList in ListView, lazy loaded as user scrolls

- fixed typo in comment in DebugType.cs

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4320 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Martin Koníček 17 years ago
parent
commit
53c34b73ee
  1. 2
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Debugger.AddIn.csproj
  2. 7
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/ObjectGraphBuilder.cs
  3. 122
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/VisualizerWPFWindow.xaml.cs
  4. 2
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/GridVisualizer/GridVisualizerWindow.xaml
  5. 50
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/GridVisualizer/GridVisualizerWindow.xaml.cs
  6. 31
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/GridVisualizer/ObjectValue.cs
  7. 2
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/GridVisualizer/ValueProviders/EnumerableValuesProvider.cs
  8. 19
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/GridVisualizer/ValueProviders/IListValuesProvider.cs
  9. 53
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/GridVisualizer/ValueProviders/ListValuesProvider.cs
  10. 192
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/GridVisualizer/VirtualizingCollection.cs
  11. 2
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Metadata/DebugType.cs

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

@ -208,7 +208,9 @@ @@ -208,7 +208,9 @@
<Compile Include="Src\Visualizers\GridVisualizer\ObjectValue.cs" />
<Compile Include="Src\Visualizers\GridVisualizer\ShowGridVisualizerCommand.cs" />
<Compile Include="Src\Visualizers\GridVisualizer\ValueProviders\EnumerableValuesProvider.cs" />
<Compile Include="Src\Visualizers\GridVisualizer\ValueProviders\IListValuesProvider.cs" />
<Compile Include="Src\Visualizers\GridVisualizer\ValueProviders\ListValuesProvider.cs" />
<Compile Include="Src\Visualizers\GridVisualizer\VirtualizingCollection.cs" />
<Compile Include="Src\Visualizers\ObjectProperty.cs" />
<Compile Include="Src\Visualizers\Utils\DebuggerHelpers.cs" />
<Compile Include="Src\Visualizers\Utils\DictionaryExtensions.cs" />

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

@ -74,8 +74,8 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -74,8 +74,8 @@ namespace Debugger.AddIn.Visualizers.Graph
{
this.debuggerService = debuggerService;
DebugType helpersType = DebugType.Create(debuggerService.DebuggedProcess, null, "System.Runtime.CompilerServices.RuntimeHelpers");
this.hashCodeMethod = helpersType.GetMember("GetHashCode", BindingFlags.Public | BindingFlags.Static | BindingFlags.Method | BindingFlags.IncludeSuperType) as MethodInfo;
DebugType typeRuntimeHelpers = DebugType.Create(debuggerService.DebuggedProcess, null, "System.Runtime.CompilerServices.RuntimeHelpers");
this.hashCodeMethod = typeRuntimeHelpers.GetMember("GetHashCode", BindingFlags.Public | BindingFlags.Static | BindingFlags.Method | BindingFlags.IncludeSuperType) as MethodInfo;
}
/// <summary>
@ -140,6 +140,7 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -140,6 +140,7 @@ namespace Debugger.AddIn.Visualizers.Graph
/// <param name="thisNode"></param>
private void loadNodeProperties(ObjectNode thisNode)
{
// take all properties for this value (type = value's real type)
foreach(Expression memberExpr in thisNode.DebuggerValue.Expression.AppendObjectMembers(thisNode.DebuggerValue.Type, _bindingFlags))
{
checkIsOfSupportedType(memberExpr);
@ -272,7 +273,7 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -272,7 +273,7 @@ namespace Debugger.AddIn.Visualizers.Graph
}
/// <summary>
/// Checks whether given expression's type is atomic - atomic values will be added to node's property list.
/// Checks whether given expression's type is atomic.
/// </summary>
/// <param name="expr">Expression.</param>
/// <returns>True if expression's type is atomic, False otherwise.</returns>

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

@ -23,43 +23,43 @@ using ICSharpCode.SharpDevelop.Services; @@ -23,43 +23,43 @@ using ICSharpCode.SharpDevelop.Services;
namespace Debugger.AddIn.Visualizers.Graph
{
/// <summary>
/// Interaction logic for VisualizerWPFWindow.xaml
/// </summary>
public partial class VisualizerWPFWindow : Window
{
private WindowsDebugger debuggerService;
private EnumViewModel<LayoutDirection> layoutViewModel;
private ObjectGraph objectGraph;
private ObjectGraphBuilder objectGraphBuilder;
private PositionedGraph oldPosGraph;
private PositionedGraph currentPosGraph;
private GraphDrawer graphDrawer;
/// <summary>
/// Long-lived map telling which nodes the user expanded.
/// </summary>
private ExpandedNodes expandedNodes;
/// <summary>
/// Interaction logic for VisualizerWPFWindow.xaml
/// </summary>
public partial class VisualizerWPFWindow : Window
{
private WindowsDebugger debuggerService;
private EnumViewModel<LayoutDirection> layoutViewModel;
private ObjectGraph objectGraph;
private ObjectGraphBuilder objectGraphBuilder;
private PositionedGraph oldPosGraph;
private PositionedGraph currentPosGraph;
private GraphDrawer graphDrawer;
/// <summary>
/// Long-lived map telling which nodes the user expanded.
/// </summary>
private ExpandedNodes expandedNodes;
public VisualizerWPFWindow()
{
InitializeComponent();
debuggerService = DebuggerService.CurrentDebugger as WindowsDebugger;
public VisualizerWPFWindow()
{
InitializeComponent();
debuggerService = DebuggerService.CurrentDebugger as WindowsDebugger;
if (debuggerService == null)
throw new ApplicationException("Only windows debugger is currently supported");
debuggerService.IsProcessRunningChanged += new EventHandler(debuggerService_IsProcessRunningChanged);
debuggerService.DebugStopped += new EventHandler(_debuggerService_DebugStopped);
this.layoutViewModel = new EnumViewModel<LayoutDirection>();
this.layoutViewModel.PropertyChanged += new PropertyChangedEventHandler(layoutViewModel_PropertyChanged);
this.DataContext = this.layoutViewModel;
this.graphDrawer = new GraphDrawer(this.canvas);
this.expandedNodes = new ExpandedNodes();
this.layoutViewModel.PropertyChanged += new PropertyChangedEventHandler(layoutViewModel_PropertyChanged);
this.DataContext = this.layoutViewModel;
this.graphDrawer = new GraphDrawer(this.canvas);
this.expandedNodes = new ExpandedNodes();
}
public void debuggerService_IsProcessRunningChanged(object sender, EventArgs e)
@ -76,33 +76,33 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -76,33 +76,33 @@ namespace Debugger.AddIn.Visualizers.Graph
debuggerService.IsProcessRunningChanged -= new EventHandler(debuggerService_IsProcessRunningChanged);
this.Close();
}
private void Inspect_Button_Click(object sender, RoutedEventArgs e)
{
private void Inspect_Button_Click(object sender, RoutedEventArgs e)
{
refreshGraph();
}
void layoutViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "SelectedEnumValue") // TODO should be special event for enum value change
{
layoutGraph(this.objectGraph);
}
}
void refreshGraph()
}
void layoutViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
this.objectGraph = rebuildGraph();
layoutGraph(this.objectGraph);
if (e.PropertyName == "SelectedEnumValue") // TODO should be special event for enum value change
{
layoutGraph(this.objectGraph);
}
}
void refreshGraph()
{
this.objectGraph = rebuildGraph();
layoutGraph(this.objectGraph);
//GraphDrawer drawer = new GraphDrawer(graph);
//drawer.Draw(canvas);
}
ObjectGraph rebuildGraph()
{
this.objectGraphBuilder = new ObjectGraphBuilder(debuggerService);
ObjectGraph rebuildGraph()
{
this.objectGraphBuilder = new ObjectGraphBuilder(debuggerService);
try
{
{
ICSharpCode.Core.LoggingService.Debug("Debugger visualizer: Building graph for expression: " + txtExpression.Text);
return this.objectGraphBuilder.BuildGraphForExpression(txtExpression.Text, this.expandedNodes);
}
@ -116,21 +116,21 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -116,21 +116,21 @@ namespace Debugger.AddIn.Visualizers.Graph
guiHandleException(ex);
return null;
}
}
void layoutGraph(ObjectGraph graph)
{
ICSharpCode.Core.LoggingService.Debug("Debugger visualizer: Calculating graph layout");
Layout.TreeLayouter layouter = new Layout.TreeLayouter();
this.oldPosGraph = this.currentPosGraph;
}
void layoutGraph(ObjectGraph graph)
{
ICSharpCode.Core.LoggingService.Debug("Debugger visualizer: Calculating graph layout");
Layout.TreeLayouter layouter = new Layout.TreeLayouter();
this.oldPosGraph = this.currentPosGraph;
this.currentPosGraph = layouter.CalculateLayout(graph, layoutViewModel.SelectedEnumValue, this.expandedNodes);
registerExpandCollapseEvents(this.currentPosGraph);
var graphDiff = new GraphMatcher().MatchGraphs(oldPosGraph, currentPosGraph);
this.graphDrawer.StartAnimation(oldPosGraph, currentPosGraph, graphDiff);
//this.graphDrawer.Draw(currentGraph);
}
}
void guiHandleException(System.Exception ex)
{
@ -165,5 +165,5 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -165,5 +165,5 @@ namespace Debugger.AddIn.Visualizers.Graph
e.Property.ObjectProperty.TargetNode = null;
layoutGraph(this.objectGraph);
}
}
}
}

2
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/GridVisualizer/GridVisualizerWindow.xaml

@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
<StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Center">Expression:</TextBlock>
<TextBox Name="txtExpression" VerticalAlignment="Center" Width="100"></TextBox>
<Button>Inspect</Button>
<Button Name="btnInspect" Click="btnInspect_Click">Inspect</Button>
</StackPanel>
</Border>

50
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/GridVisualizer/GridVisualizerWindow.xaml.cs

@ -4,7 +4,9 @@ @@ -4,7 +4,9 @@
// <owner name="Martin Koníček" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using Debugger.MetaData;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Windows;
@ -13,6 +15,8 @@ using System.Windows.Data; @@ -13,6 +15,8 @@ using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Services;
namespace Debugger.AddIn.Visualizers.GridVisualizer
{
@ -21,9 +25,55 @@ namespace Debugger.AddIn.Visualizers.GridVisualizer @@ -21,9 +25,55 @@ namespace Debugger.AddIn.Visualizers.GridVisualizer
/// </summary>
public partial class GridVisualizerWindow : Window
{
private WindowsDebugger debuggerService;
public GridVisualizerWindow()
{
InitializeComponent();
}
private void btnInspect_Click(object sender, RoutedEventArgs e)
{
this.debuggerService = DebuggerService.CurrentDebugger as WindowsDebugger;
if (debuggerService == null)
throw new ApplicationException("Only windows debugger is currently supported");
Value val = debuggerService.GetValueFromName(txtExpression.Text).GetPermanentReference();
if (val != null && !val.IsNull)
{
// search val.Type.Interfaces for IList<T>, from it, get T
DebugType iListType = val.Type.GetInterface(typeof(IList).FullName);
if (iListType != null)
{
List<DebugType> genericArguments = val.Type.GenericArguments;
if (genericArguments.Count == 1)
{
DebugType listItemType = genericArguments[0];
var valuesProvider = new ListValuesProvider(val.Expression, iListType, listItemType);
var virtCollection = new VirtualizingCollection<ObjectValue>(valuesProvider);
IList<MemberInfo> listItemTypeMembers = valuesProvider.GetItemTypeMembers();
createListViewColumns(listItemTypeMembers);
this.listView.ItemsSource = virtCollection;
}
}
}
}
private void createListViewColumns(IList<MemberInfo> itemTypeMembers)
{
var gridView = (GridView)listView.View;
gridView.Columns.Clear();
foreach (var member in itemTypeMembers)
{
GridViewColumn column = new GridViewColumn();
column.Header = member.Name;
// "{Binding Path=[Name]}"
column.DisplayMemberBinding = new Binding("[" + member.Name + "].Value");
gridView.Columns.Add(column);
}
}
}
}

31
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/GridVisualizer/ObjectValue.cs

@ -4,29 +4,46 @@ @@ -4,29 +4,46 @@
// <owner name="Martin Koníček" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using ICSharpCode.SharpDevelop.Services;
using System;
using System.Collections.Generic;
using Debugger.AddIn.Visualizers.Utils;
using Debugger.Expressions;
using Debugger.MetaData;
namespace Debugger.AddIn.Visualizers.GridVisualizer
{
/// <summary>
/// Description of ObjectValue.
/// Object in the debugee, with its properties loaded.
/// </summary>
public class ObjectValue
{
private Dictionary<string, ObjectProperty> properties = new Dictionary<string, ObjectProperty>();
/// <summary>
/// Returns property with given name.
/// </summary>
public ObjectProperty this[string key]
{
get
{
return properties.GetValue(key);
}
set
get { return properties.GetValue(key); }
set { properties[key] = value; }
}
public static ObjectValue Create(Expression expr, DebugType type, BindingFlags bindingFlags)
{
ObjectValue result = new ObjectValue();
foreach(Expression memberExpr in expr.AppendObjectMembers(type, bindingFlags))
{
properties[key] = value;
ObjectProperty property = new ObjectProperty();
property.IsAtomic = memberExpr.Evaluate(WindowsDebugger.CurrentProcess).Type.IsPrimitive;
property.Name = memberExpr.CodeTail;
property.Expression = memberExpr;
property.IsNull = memberExpr.Evaluate(WindowsDebugger.CurrentProcess).IsNull;
property.Value = memberExpr.Evaluate(WindowsDebugger.CurrentProcess).AsString;
result.properties.Add(property.Name, property);
}
return result;
}
}
}

2
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/GridVisualizer/ValueProviders/EnumerableValuesProvider.cs

@ -9,7 +9,7 @@ using Debugger.Expressions; @@ -9,7 +9,7 @@ using Debugger.Expressions;
using ICSharpCode.SharpDevelop.Services;
using System.Collections.Generic;
namespace Debugger.AddIn.Visualizers.GridVisualizer.ValueProviders
namespace Debugger.AddIn.Visualizers.GridVisualizer
{
/// <summary>
/// Provides <see cref="ObjectValue"/>s for debugee objects implementing IEnumerable.

19
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/GridVisualizer/ValueProviders/IListValuesProvider.cs

@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
// <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.GridVisualizer
{
/// <summary>
/// Can provide individial items for a lazy collection, as well as total count of items.
/// </summary>
public interface IListValuesProvider<T>
{
int GetCount();
T GetItemAt(int index);
}
}

53
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/GridVisualizer/ValueProviders/ListValuesProvider.cs

@ -5,33 +5,70 @@ @@ -5,33 +5,70 @@
// <version>$Revision$</version>
// </file>
using System;
using ICSharpCode.SharpDevelop.Services;
using Debugger.Expressions;
using Debugger.MetaData;
using ICSharpCode.SharpDevelop.Services;
using System.Collections;
using System.Collections.Generic;
namespace Debugger.AddIn.Visualizers.GridVisualizer.ValueProviders
namespace Debugger.AddIn.Visualizers.GridVisualizer
{
/// <summary>
/// Provides <see cref="ObjectValue"/>s for debugee objects implementing IList.
/// </summary>
public class ListValuesProvider
public class ListValuesProvider : IListValuesProvider<ObjectValue>
{
private WindowsDebugger debugger;
private readonly Debugger.MetaData.BindingFlags bindingFlags =
BindingFlags.Public | BindingFlags.Instance | BindingFlags.Field | BindingFlags.GetProperty;
private Expression targetObject;
private DebugType iListType;
private DebugType listItemType;
public ListValuesProvider(WindowsDebugger debuggerService, Expression targetObject)
private bool countEvaluated = false;
private int count = -1;
public ListValuesProvider(Expression targetObject, DebugType iListType, DebugType listItemType)
{
this.debugger = debuggerService;
this.targetObject = targetObject;
this.iListType = iListType;
this.listItemType = listItemType;
}
public int GetCount()
{
return -1;
if (!countEvaluated)
{
this.count = evaluateCount();
}
return this.count;
}
public ObjectValue GetItemAt(int index)
{
return null;
PropertyInfo itemProperty = iListType.GetProperty("Item");
Expression itemExpr = targetObject.AppendMemberReference(itemProperty, new PrimitiveExpression(index));
return ObjectValue.Create(itemExpr, this.listItemType, this.bindingFlags);
}
public IList<MemberInfo> GetItemTypeMembers()
{
return listItemType.GetMembers(this.bindingFlags);
}
private int evaluateCount()
{
PropertyInfo countProperty = iListType.GetInterface(typeof(ICollection).FullName).GetProperty("Count");
Expression countExpr = targetObject.AppendPropertyReference(countProperty);
int count = 0;
try {
// Do not get string representation since it can be printed in hex later
Value countValue = countExpr.Evaluate(WindowsDebugger.CurrentProcess);
count = (int)countValue.PrimitiveValue;
} catch (GetValueException) {
count = -1;
}
return count;
}
}
}

192
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/GridVisualizer/VirtualizingCollection.cs

@ -0,0 +1,192 @@ @@ -0,0 +1,192 @@
// <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;
using System.Collections.Generic;
namespace Debugger.AddIn.Visualizers.GridVisualizer
{
/// <summary>
/// IList&lt;T&gt; with data vitualization - the indexer is lazy, uses IListValuesProvider to obtain values.
/// </summary>
public class VirtualizingCollection<T> : IList<T>, IList
{
private IListValuesProvider<T> valueProvider;
private Dictionary<int, T> itemCache = new Dictionary<int, T>();
public VirtualizingCollection(IListValuesProvider<T> valueProvider)
{
this.valueProvider = valueProvider;
}
public int Count
{
get { return this.valueProvider.GetCount(); }
}
public T this[int index]
{
get
{
T cachedItem;
if (!itemCache.TryGetValue(index, out cachedItem))
{
cachedItem = this.valueProvider.GetItemAt(index);
this.itemCache[index] = cachedItem;
}
return cachedItem;
}
set
{
throw new NotImplementedException();
}
}
#region IList<T> Members
public int IndexOf(T item)
{
return -1;
}
public void Insert(int index, T item)
{
throw new NotImplementedException();
}
public void RemoveAt(int index)
{
throw new NotImplementedException();
}
#endregion
#region ICollection<T> Members
public void Add(T item)
{
throw new NotImplementedException();
}
public void Clear()
{
throw new NotImplementedException();
}
public bool Contains(T item)
{
throw new NotImplementedException();
}
public void CopyTo(T[] array, int arrayIndex)
{
throw new NotImplementedException();
}
public bool IsReadOnly
{
get { return true; }
}
public bool Remove(T item)
{
throw new NotImplementedException();
}
#endregion
#region IEnumerable<T> Members
/// <summary>
/// Should be avoided on large collections due to performance.
/// </summary>
/// <returns></returns>
public IEnumerator<T> GetEnumerator()
{
for (int i = 0; i < this.Count; i++)
{
yield return this[i];
}
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
#endregion
#region IList Members
public int Add(object value)
{
throw new NotImplementedException();
}
public bool Contains(object value)
{
throw new NotImplementedException();
}
public int IndexOf(object value)
{
return IndexOf((T)value);
}
public void Insert(int index, object value)
{
throw new NotImplementedException();
}
public bool IsFixedSize
{
get { return false; }
}
public void Remove(object value)
{
throw new NotImplementedException();
}
object IList.this[int index]
{
get
{
return this[index];
}
set
{
throw new NotImplementedException();
}
}
#endregion
#region ICollection Members
public void CopyTo(Array array, int index)
{
throw new NotImplementedException();
}
public bool IsSynchronized
{
get { return false; }
}
public object SyncRoot
{
get { return this; }
}
#endregion
}
}

2
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Metadata/DebugType.cs

@ -144,7 +144,7 @@ namespace Debugger.MetaData @@ -144,7 +144,7 @@ namespace Debugger.MetaData
}
}
/// <summary> Gets generics arguments for a type or an emtpy array for non-generic types. </summary>
/// <summary> Gets generics arguments for a type or an empty List for non-generic types. </summary>
public List<DebugType> GenericArguments {
get {
if (this.IsArray || this.IsPointer) {

Loading…
Cancel
Save