Browse Source

Prepare TreeView filtering.

pull/1/head
Daniel Grunwald 15 years ago
parent
commit
1c8602df06
  1. 81
      ILSpy/AssemblyList.cs
  2. 70
      ILSpy/AssemblyListTreeNode.cs
  3. 2
      ILSpy/AssemblyReferenceTreeNode.cs
  4. 35
      ILSpy/AssemblyTreeNode.cs
  5. 109
      ILSpy/BaseTypesTreeNode.cs
  6. 2
      ILSpy/EventTreeNode.cs
  7. 7
      ILSpy/ExtensionMethods.cs
  8. 2
      ILSpy/FieldTreeNode.cs
  9. 45
      ILSpy/FilterSettings.cs
  10. 10
      ILSpy/ILSpy.csproj
  11. 136
      ILSpy/ILSpyTreeNode.cs
  12. BIN
      ILSpy/Images/Find.png
  13. 1
      ILSpy/Images/Images.cs
  14. BIN
      ILSpy/Images/Library.png
  15. 1
      ILSpy/MainWindow.xaml
  16. 11
      ILSpy/MainWindow.xaml.cs
  17. 4
      ILSpy/MethodTreeNode.cs
  18. 6
      ILSpy/ModuleReferenceTreeNode.cs
  19. 2
      ILSpy/NamespaceTreeNode.cs
  20. 2
      ILSpy/PropertyTreeNode.cs
  21. 2
      ILSpy/ReferenceFolderTreeNode.cs
  22. 2
      ILSpy/TypeTreeNode.cs
  23. 2
      SharpTreeView/ExtensionMethods.cs

81
ILSpy/AssemblyList.cs

@ -0,0 +1,81 @@
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Concurrent;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using Mono.Cecil;
namespace ICSharpCode.ILSpy
{
/// <summary>
/// Description of AssemblyList.
/// </summary>
class AssemblyList
{
public readonly ObservableCollection<AssemblyTreeNode> Assemblies = new ObservableCollection<AssemblyTreeNode>();
ConcurrentDictionary<TypeDefinition, TypeTreeNode> typeDict = new ConcurrentDictionary<TypeDefinition, TypeTreeNode>();
public void RegisterTypeNode(TypeTreeNode node)
{
// called on background loading thread, so we need to use a ConcurrentDictionary
typeDict[node.TypeDefinition] = node;
}
public TypeTreeNode FindTypeNode(TypeDefinition def)
{
if (def.DeclaringType != null) {
TypeTreeNode decl = FindTypeNode(def.DeclaringType);
if (decl != null) {
decl.EnsureLazyChildren();
return decl.Children.OfType<TypeTreeNode>().FirstOrDefault(t => t.TypeDefinition == def);
}
} else {
TypeTreeNode node;
if (typeDict.TryGetValue(def, out node)) {
// Ensure that the node is connected to the tree
node.ParentAssemblyNode.EnsureLazyChildren();
// Validate that the node wasn't removed due to visibility settings:
if (node.Ancestors().OfType<AssemblyListTreeNode>().Any(n => n.AssemblyList == this))
return node;
}
}
return null;
}
public AssemblyTreeNode OpenAssembly(string file)
{
App.Current.Dispatcher.VerifyAccess();
file = Path.GetFullPath(file);
foreach (AssemblyTreeNode node in this.Assemblies) {
if (file.Equals(node.FileName, StringComparison.OrdinalIgnoreCase))
return node;
}
var newNode = new AssemblyTreeNode(file, this);
this.Assemblies.Add(newNode);
return newNode;
}
}
}

70
ILSpy/AssemblyListTreeNode.cs

@ -18,12 +18,14 @@
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Specialized;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Windows; using System.Windows;
using ICSharpCode.TreeView; using ICSharpCode.TreeView;
using Mono.Cecil; using Mono.Cecil;
@ -32,8 +34,23 @@ namespace ICSharpCode.ILSpy
/// <summary> /// <summary>
/// Represents a list of assemblies. /// Represents a list of assemblies.
/// </summary> /// </summary>
sealed class AssemblyListTreeNode : SharpTreeNode sealed class AssemblyListTreeNode : ILSpyTreeNode<AssemblyTreeNode>
{ {
readonly AssemblyList assemblyList;
public AssemblyList AssemblyList {
get { return assemblyList; }
}
public AssemblyListTreeNode(AssemblyList assemblyList)
: base(assemblyList.Assemblies)
{
if (assemblyList == null)
throw new ArgumentNullException("assemblyList");
this.assemblyList = assemblyList;
this.FilterSettings = new FilterSettings(); // default filter
}
public override bool CanDelete(SharpTreeNode[] nodes) public override bool CanDelete(SharpTreeNode[] nodes)
{ {
return nodes.All(n => n is AssemblyTreeNode); return nodes.All(n => n is AssemblyTreeNode);
@ -46,8 +63,8 @@ namespace ICSharpCode.ILSpy
public override void DeleteCore(SharpTreeNode[] nodes) public override void DeleteCore(SharpTreeNode[] nodes)
{ {
foreach (SharpTreeNode node in nodes) foreach (AssemblyTreeNode node in nodes)
this.Children.Remove(node); assemblyList.Assemblies.Remove(node);
} }
public override DropEffect CanDrop(IDataObject data, DropEffect requestedEffect) public override DropEffect CanDrop(IDataObject data, DropEffect requestedEffect)
@ -68,7 +85,7 @@ namespace ICSharpCode.ILSpy
if (files != null) { if (files != null) {
var nodes = (from file in files var nodes = (from file in files
where file != null where file != null
select OpenAssembly(file) into node select assemblyList.OpenAssembly(file) into node
where node != null where node != null
select node).Distinct().ToList(); select node).Distinct().ToList();
foreach (AssemblyTreeNode node in nodes) { foreach (AssemblyTreeNode node in nodes) {
@ -84,51 +101,6 @@ namespace ICSharpCode.ILSpy
} }
} }
public AssemblyTreeNode OpenAssembly(string file)
{
App.Current.Dispatcher.VerifyAccess();
file = Path.GetFullPath(file);
foreach (AssemblyTreeNode node in this.Children) {
if (file.Equals(node.FileName, StringComparison.OrdinalIgnoreCase))
return node;
}
var newNode = new AssemblyTreeNode(file, this);
this.Children.Add(newNode);
return newNode;
}
public Action<SharpTreeNode> Select = delegate {}; public Action<SharpTreeNode> Select = delegate {};
ConcurrentDictionary<TypeDefinition, TypeTreeNode> typeDict = new ConcurrentDictionary<TypeDefinition, TypeTreeNode>();
public void RegisterTypeNode(TypeTreeNode node)
{
// called on background loading thread, so we need to use a ConcurrentDictionary
typeDict[node.TypeDefinition] = node;
}
public TypeTreeNode FindTypeNode(TypeDefinition def)
{
if (def.DeclaringType != null) {
TypeTreeNode decl = FindTypeNode(def.DeclaringType);
if (decl != null) {
decl.EnsureLazyChildren();
return decl.Children.OfType<TypeTreeNode>().FirstOrDefault(t => t.TypeDefinition == def);
}
} else {
TypeTreeNode node;
if (typeDict.TryGetValue(def, out node)) {
// Ensure that the node is connected to the tree
node.ParentAssemblyNode.EnsureLazyChildren();
// Validate that the node wasn't removed due to visibility settings:
if (node.Ancestors().Contains(this))
return node;
}
}
return null;
}
} }
} }

2
ILSpy/AssemblyReferenceTreeNode.cs

@ -26,7 +26,7 @@ namespace ICSharpCode.ILSpy
/// <summary> /// <summary>
/// Node within assembly reference list. /// Node within assembly reference list.
/// </summary> /// </summary>
sealed class AssemblyReferenceTreeNode : SharpTreeNode sealed class AssemblyReferenceTreeNode : ILSpyTreeNode
{ {
readonly AssemblyNameReference r; readonly AssemblyNameReference r;
readonly AssemblyTreeNode parentAssembly; readonly AssemblyTreeNode parentAssembly;

35
ILSpy/AssemblyTreeNode.cs

@ -29,9 +29,9 @@ using Mono.Cecil;
namespace ICSharpCode.ILSpy namespace ICSharpCode.ILSpy
{ {
sealed class AssemblyTreeNode : SharpTreeNode sealed class AssemblyTreeNode : ILSpyTreeNode
{ {
readonly AssemblyListTreeNode assemblyList; readonly AssemblyList assemblyList;
readonly string fileName; readonly string fileName;
string shortName; string shortName;
readonly Task<AssemblyDefinition> assemblyTask; readonly Task<AssemblyDefinition> assemblyTask;
@ -39,7 +39,7 @@ namespace ICSharpCode.ILSpy
readonly Dictionary<string, NamespaceTreeNode> namespaces = new Dictionary<string, NamespaceTreeNode>(); readonly Dictionary<string, NamespaceTreeNode> namespaces = new Dictionary<string, NamespaceTreeNode>();
readonly SynchronizationContext syncContext; readonly SynchronizationContext syncContext;
public AssemblyTreeNode(string fileName, AssemblyListTreeNode assemblyList) public AssemblyTreeNode(string fileName, AssemblyList assemblyList)
{ {
if (fileName == null) if (fileName == null)
throw new ArgumentNullException("fileName"); throw new ArgumentNullException("fileName");
@ -133,8 +133,6 @@ namespace ICSharpCode.ILSpy
ns.Children.Clear(); ns.Children.Clear();
} }
foreach (TypeTreeNode type in classes) { foreach (TypeTreeNode type in classes) {
if (showInternalAPI == false && type.IsPublicAPI == false)
continue;
NamespaceTreeNode ns; NamespaceTreeNode ns;
if (!namespaces.TryGetValue(type.Namespace, out ns)) { if (!namespaces.TryGetValue(type.Namespace, out ns)) {
ns = new NamespaceTreeNode(type.Namespace); ns = new NamespaceTreeNode(type.Namespace);
@ -148,31 +146,6 @@ namespace ICSharpCode.ILSpy
} }
} }
/// <summary>
/// Invalidates the list of children.
/// </summary>
void InvalidateChildren()
{
this.Children.Clear();
if (this.IsExpanded)
this.LoadChildren();
else
this.LazyLoading = true;
}
bool showInternalAPI = true;
public bool ShowInternalAPI {
get { return showInternalAPI; }
set {
if (showInternalAPI != value) {
showInternalAPI = value;
InvalidateChildren();
RaisePropertyChanged("ShowInternalAPI");
}
}
}
public override bool CanDrag(SharpTreeNode[] nodes) public override bool CanDrag(SharpTreeNode[] nodes)
{ {
return nodes.All(n => n is AssemblyTreeNode); return nodes.All(n => n is AssemblyTreeNode);
@ -204,7 +177,7 @@ namespace ICSharpCode.ILSpy
public AssemblyTreeNode LookupReferencedAssembly(string fullName) public AssemblyTreeNode LookupReferencedAssembly(string fullName)
{ {
foreach (AssemblyTreeNode node in assemblyList.Children) { foreach (AssemblyTreeNode node in assemblyList.Assemblies) {
if (fullName.Equals(node.AssemblyDefinition.FullName, StringComparison.OrdinalIgnoreCase)) if (fullName.Equals(node.AssemblyDefinition.FullName, StringComparison.OrdinalIgnoreCase))
return node; return node;
} }

109
ILSpy/BaseTypesTreeNode.cs

@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using ICSharpCode.TreeView; using ICSharpCode.TreeView;
using Mono.Cecil; using Mono.Cecil;
@ -26,7 +27,7 @@ namespace ICSharpCode.ILSpy
/// <summary> /// <summary>
/// Lists the base types of a class. /// Lists the base types of a class.
/// </summary> /// </summary>
sealed class BaseTypesTreeNode : SharpTreeNode sealed class BaseTypesTreeNode : ILSpyTreeNode<BaseTypesEntryNode>
{ {
readonly TypeDefinition type; readonly TypeDefinition type;
@ -49,70 +50,70 @@ namespace ICSharpCode.ILSpy
AddBaseTypes(this.Children, type); AddBaseTypes(this.Children, type);
} }
static void AddBaseTypes(SharpTreeNodeCollection children, TypeDefinition type) internal static void AddBaseTypes(ObservableCollection<BaseTypesEntryNode> children, TypeDefinition type)
{ {
if (type.BaseType != null) if (type.BaseType != null)
children.Add(new EntryNode(type.BaseType, false)); children.Add(new BaseTypesEntryNode(type.BaseType, false));
foreach (TypeReference i in type.Interfaces) { foreach (TypeReference i in type.Interfaces) {
children.Add(new EntryNode(i, true)); children.Add(new BaseTypesEntryNode(i, true));
} }
} }
}
sealed class BaseTypesEntryNode : ILSpyTreeNode<BaseTypesEntryNode>
{
TypeReference tr;
TypeDefinition def;
bool isInterface;
sealed class EntryNode : SharpTreeNode public BaseTypesEntryNode(TypeReference tr, bool isInterface)
{ {
TypeReference tr; if (tr == null)
TypeDefinition def; throw new ArgumentNullException("tr");
bool isInterface; this.tr = tr;
this.def = tr.Resolve();
public EntryNode(TypeReference tr, bool isInterface) this.isInterface = isInterface;
{ this.LazyLoading = true;
if (tr == null) }
throw new ArgumentNullException("tr");
this.tr = tr; public override bool ShowExpander {
this.def = tr.Resolve(); get {
this.isInterface = isInterface; return def != null && (def.BaseType != null || def.HasInterfaces);
this.LazyLoading = true;
}
public override bool ShowExpander {
get {
return def != null && (def.BaseType != null || def.HasInterfaces);
}
}
public override object Text {
get { return tr.FullName; }
} }
}
public override object Icon {
get { public override object Text {
if (def != null) get { return tr.FullName; }
return TypeTreeNode.GetIcon(def); }
else
return isInterface ? Images.Interface : Images.Class; public override object Icon {
} get {
if (def != null)
return TypeTreeNode.GetIcon(def);
else
return isInterface ? Images.Interface : Images.Class;
} }
}
protected override void LoadChildren()
{ protected override void LoadChildren()
{
if (def != null)
BaseTypesTreeNode.AddBaseTypes(this.Children, def);
}
public override void ActivateItem(System.Windows.RoutedEventArgs e)
{
// on item activation, try to resolve once again (maybe the user loaded the assembly in the meantime)
if (def == null) {
def = tr.Resolve();
if (def != null) if (def != null)
AddBaseTypes(this.Children, def); this.LazyLoading = true; // re-load children
} }
if (def != null) {
public override void ActivateItem(System.Windows.RoutedEventArgs e) var assemblyListNode = this.Ancestors().OfType<AssemblyListTreeNode>().FirstOrDefault();
{ if (assemblyListNode != null) {
// on item activation, try to resolve once again (maybe the user loaded the assembly in the meantime) assemblyListNode.Select(assemblyListNode.AssemblyList.FindTypeNode(def));
if (def == null) { e.Handled = true;
def = tr.Resolve();
if (def != null)
this.LazyLoading = true; // re-load children
}
if (def != null) {
var assemblyListNode = this.Ancestors().OfType<AssemblyListTreeNode>().FirstOrDefault();
if (assemblyListNode != null) {
assemblyListNode.Select(assemblyListNode.FindTypeNode(def));
e.Handled = true;
}
} }
} }
} }

2
ILSpy/EventTreeNode.cs

@ -25,7 +25,7 @@ namespace ICSharpCode.ILSpy
/// <summary> /// <summary>
/// Represents an event in the TreeView. /// Represents an event in the TreeView.
/// </summary> /// </summary>
sealed class EventTreeNode : SharpTreeNode sealed class EventTreeNode : ILSpyTreeNode
{ {
readonly EventDefinition ev; readonly EventDefinition ev;

7
ILSpy/ExtensionMethods.cs

@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Collections.Generic;
using System.Windows; using System.Windows;
using System.Windows.Markup; using System.Windows.Markup;
@ -27,6 +28,12 @@ namespace ICSharpCode.ILSpy
/// </summary> /// </summary>
public static class ExtensionMethods public static class ExtensionMethods
{ {
public static void AddRange<T>(this ICollection<T> list, IEnumerable<T> items)
{
foreach (T item in items)
list.Add(item);
}
/// <summary> /// <summary>
/// Sets the value of a dependency property on <paramref name="targetObject"/> using a markup extension. /// Sets the value of a dependency property on <paramref name="targetObject"/> using a markup extension.
/// </summary> /// </summary>

2
ILSpy/FieldTreeNode.cs

@ -25,7 +25,7 @@ namespace ICSharpCode.ILSpy
/// <summary> /// <summary>
/// Represents a field in the TreeView. /// Represents a field in the TreeView.
/// </summary> /// </summary>
sealed class FieldTreeNode : SharpTreeNode sealed class FieldTreeNode : ILSpyTreeNode
{ {
readonly FieldDefinition field; readonly FieldDefinition field;

45
ILSpy/IDecompilableNode.cs → ILSpy/FilterSettings.cs

@ -17,14 +17,53 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.ComponentModel;
namespace ICSharpCode.ILSpy namespace ICSharpCode.ILSpy
{ {
/// <summary> /// <summary>
/// Interface for decompilable tree nodes. /// Represents the filters applied to the tree view.
/// </summary> /// </summary>
public interface IDecompilableNode public class FilterSettings : INotifyPropertyChanged
{ {
void Decompile(Language language, ITextOutput output); string searchTerm;
public string SearchTerm {
get { return searchTerm; }
set {
if (searchTerm != value) {
searchTerm = value;
OnPropertyChanged("SearchTerm");
}
}
}
bool showInternalApi;
public bool ShowInternalApi {
get { return showInternalApi; }
set {
if (showInternalApi != value) {
showInternalApi = value;
OnPropertyChanged("ShowInternalAPI");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public FilterSettings Clone()
{
FilterSettings f = (FilterSettings)MemberwiseClone();
f.PropertyChanged = null;
return f;
}
} }
} }

10
ILSpy/ILSpy.csproj

@ -68,6 +68,7 @@
<SubType>Code</SubType> <SubType>Code</SubType>
<DependentUpon>App.xaml</DependentUpon> <DependentUpon>App.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="AssemblyList.cs" />
<Compile Include="AssemblyListTreeNode.cs" /> <Compile Include="AssemblyListTreeNode.cs" />
<Compile Include="AssemblyReferenceTreeNode.cs" /> <Compile Include="AssemblyReferenceTreeNode.cs" />
<Compile Include="AssemblyTreeNode.cs" /> <Compile Include="AssemblyTreeNode.cs" />
@ -76,9 +77,10 @@
<Compile Include="EventTreeNode.cs" /> <Compile Include="EventTreeNode.cs" />
<Compile Include="ExtensionMethods.cs" /> <Compile Include="ExtensionMethods.cs" />
<Compile Include="FieldTreeNode.cs" /> <Compile Include="FieldTreeNode.cs" />
<Compile Include="FilterSettings.cs" />
<Compile Include="Fusion.cs" /> <Compile Include="Fusion.cs" />
<Compile Include="GacInterop.cs" /> <Compile Include="GacInterop.cs" />
<Compile Include="IDecompilableNode.cs" /> <Compile Include="ILSpyTreeNode.cs" />
<Compile Include="ITextOutput.cs" /> <Compile Include="ITextOutput.cs" />
<Compile Include="Language.cs" /> <Compile Include="Language.cs" />
<Compile Include="Images\Images.cs" /> <Compile Include="Images\Images.cs" />
@ -177,5 +179,11 @@
<ItemGroup> <ItemGroup>
<Resource Include="Images\Property.png" /> <Resource Include="Images\Property.png" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Resource Include="Images\Find.png" />
</ItemGroup>
<ItemGroup>
<Resource Include="Images\Library.png" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
</Project> </Project>

136
ILSpy/ILSpyTreeNode.cs

@ -0,0 +1,136 @@
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using ICSharpCode.TreeView;
namespace ICSharpCode.ILSpy
{
abstract class ILSpyTreeNodeBase : SharpTreeNode
{
FilterSettings filterSettings;
public FilterSettings FilterSettings {
get { return filterSettings; }
set {
if (filterSettings != value) {
filterSettings = value;
OnFilterSettingsChanged();
}
}
}
protected abstract void OnFilterSettingsChanged();
public virtual FilterResult Filter(FilterSettings settings)
{
return FilterResult.Match;
}
public virtual void Decompile(Language language, ITextOutput output)
{
}
}
public enum FilterResult
{
Hidden,
Match
}
/// <summary>
/// Base class for ILSpy tree nodes.
/// </summary>
class ILSpyTreeNode<T> : ILSpyTreeNodeBase where T : ILSpyTreeNodeBase
{
public ILSpyTreeNode()
: this(new ObservableCollection<T>())
{
}
public ILSpyTreeNode(ObservableCollection<T> children)
{
if (children == null)
throw new ArgumentNullException("children");
this.Children = children;
children.CollectionChanged += children_CollectionChanged;
}
void children_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action) {
case NotifyCollectionChangedAction.Add:
if (e.NewItems.Count == 1 && e.NewStartingIndex == this.Children.Count - 1) {
FilterChild((T)e.NewItems[0]);
break;
} else {
goto default;
}
default:
ResetChildren();
break;
}
}
void ResetChildren()
{
base.Children.Clear();
foreach (T child in this.Children) {
FilterChild(child);
}
}
void FilterChild(T child)
{
switch (child.Filter(this.FilterSettings)) {
case FilterResult.Hidden:
// don't add to base.Children
break;
case FilterResult.Match:
base.Children.Add(child);
child.FilterSettings = StripSearchTerm(this.FilterSettings);
break;
default:
throw new InvalidEnumArgumentException();
}
}
FilterSettings StripSearchTerm(FilterSettings filterSettings)
{
if (filterSettings == null)
return null;
if (!string.IsNullOrEmpty(filterSettings.SearchTerm)) {
filterSettings = filterSettings.Clone();
filterSettings.SearchTerm = null;
}
return filterSettings;
}
protected override void OnFilterSettingsChanged()
{
ResetChildren();
}
public new readonly ObservableCollection<T> Children;
}
class ILSpyTreeNode : ILSpyTreeNode<ILSpyTreeNodeBase> {}
}

BIN
ILSpy/Images/Find.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 714 B

1
ILSpy/Images/Images.cs

@ -16,6 +16,7 @@ namespace ICSharpCode.ILSpy
} }
public static readonly BitmapImage Assembly = LoadBitmap("Assembly"); public static readonly BitmapImage Assembly = LoadBitmap("Assembly");
public static readonly BitmapImage Library = LoadBitmap("Library");
public static readonly BitmapImage Namespace = LoadBitmap("NameSpace"); public static readonly BitmapImage Namespace = LoadBitmap("NameSpace");
public static readonly BitmapImage ReferenceFolderOpen = LoadBitmap("ReferenceFolder.Open"); public static readonly BitmapImage ReferenceFolderOpen = LoadBitmap("ReferenceFolder.Open");

BIN
ILSpy/Images/Library.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 B

1
ILSpy/MainWindow.xaml

@ -101,7 +101,6 @@
Grid.Column="2"> Grid.Column="2">
<ae:TextEditor <ae:TextEditor
Name="textEditor" Name="textEditor"
SyntaxHighlighting="C#"
FontFamily="Consolas" FontFamily="Consolas"
FontSize="10pt" FontSize="10pt"
IsReadOnly="True" IsReadOnly="True"

11
ILSpy/MainWindow.xaml.cs

@ -35,7 +35,7 @@ namespace ICSharpCode.ILSpy
/// </summary> /// </summary>
public partial class MainWindow : Window public partial class MainWindow : Window
{ {
AssemblyListTreeNode assemblyList = new AssemblyListTreeNode(); AssemblyList assemblyList = new AssemblyList();
static readonly Assembly[] initialAssemblies = { static readonly Assembly[] initialAssemblies = {
typeof(object).Assembly, typeof(object).Assembly,
@ -55,9 +55,10 @@ namespace ICSharpCode.ILSpy
{ {
InitializeComponent(); InitializeComponent();
textEditor.Text = "// Welcome to ILSpy!"; textEditor.Text = "Welcome to ILSpy!";
treeView.Root = assemblyList; AssemblyListTreeNode assemblyListTreeNode = new AssemblyListTreeNode(assemblyList);
assemblyList.Select = delegate(SharpTreeNode obj) { treeView.Root = assemblyListTreeNode;
assemblyListTreeNode.Select = delegate(SharpTreeNode obj) {
if (obj != null) { if (obj != null) {
foreach (SharpTreeNode node in obj.Ancestors()) foreach (SharpTreeNode node in obj.Ancestors())
node.IsExpanded = true; node.IsExpanded = true;
@ -128,7 +129,7 @@ namespace ICSharpCode.ILSpy
try { try {
textEditor.SyntaxHighlighting = ILSpy.Language.Current.SyntaxHighlighting; textEditor.SyntaxHighlighting = ILSpy.Language.Current.SyntaxHighlighting;
SmartTextOutput textOutput = new SmartTextOutput(); SmartTextOutput textOutput = new SmartTextOutput();
foreach (var node in treeView.SelectedItems.OfType<IDecompilableNode>()) { foreach (var node in treeView.SelectedItems.OfType<ILSpyTreeNode>()) {
node.Decompile(ILSpy.Language.Current, textOutput); node.Decompile(ILSpy.Language.Current, textOutput);
} }
textEditor.Text = textOutput.ToString(); textEditor.Text = textOutput.ToString();

4
ILSpy/MethodTreeNode.cs

@ -26,7 +26,7 @@ namespace ICSharpCode.ILSpy
/// <summary> /// <summary>
/// Tree Node representing a field, method, property, or event. /// Tree Node representing a field, method, property, or event.
/// </summary> /// </summary>
sealed class MethodTreeNode : SharpTreeNode, IDecompilableNode sealed class MethodTreeNode : ILSpyTreeNode
{ {
MethodDefinition method; MethodDefinition method;
@ -66,7 +66,7 @@ namespace ICSharpCode.ILSpy
} }
} }
public void Decompile(Language language, ITextOutput output) public override void Decompile(Language language, ITextOutput output)
{ {
language.Decompile(method, output); language.Decompile(method, output);
} }

6
ILSpy/ModuleReferenceTreeNode.cs

@ -25,7 +25,7 @@ namespace ICSharpCode.ILSpy
/// <summary> /// <summary>
/// Module reference in ReferenceFolderTreeNode. /// Module reference in ReferenceFolderTreeNode.
/// </summary> /// </summary>
public class ModuleReferenceTreeNode : SharpTreeNode sealed class ModuleReferenceTreeNode : ILSpyTreeNode
{ {
ModuleReference r; ModuleReference r;
@ -39,5 +39,9 @@ namespace ICSharpCode.ILSpy
public override object Text { public override object Text {
get { return r.Name; } get { return r.Name; }
} }
public override object Icon {
get { return Images.Library; }
}
} }
} }

2
ILSpy/NamespaceTreeNode.cs

@ -22,7 +22,7 @@ using ICSharpCode.TreeView;
namespace ICSharpCode.ILSpy namespace ICSharpCode.ILSpy
{ {
sealed class NamespaceTreeNode : SharpTreeNode sealed class NamespaceTreeNode : ILSpyTreeNode
{ {
string name; string name;

2
ILSpy/PropertyTreeNode.cs

@ -25,7 +25,7 @@ namespace ICSharpCode.ILSpy
/// <summary> /// <summary>
/// Represents a property in the TreeView. /// Represents a property in the TreeView.
/// </summary> /// </summary>
sealed class PropertyTreeNode : SharpTreeNode sealed class PropertyTreeNode : ILSpyTreeNode
{ {
readonly PropertyDefinition property; readonly PropertyDefinition property;
readonly bool isIndexer; readonly bool isIndexer;

2
ILSpy/ReferenceFolderTreeNode.cs

@ -25,7 +25,7 @@ namespace ICSharpCode.ILSpy
/// <summary> /// <summary>
/// References folder. /// References folder.
/// </summary> /// </summary>
sealed class ReferenceFolderTreeNode : SharpTreeNode sealed class ReferenceFolderTreeNode : ILSpyTreeNode
{ {
readonly ModuleDefinition module; readonly ModuleDefinition module;
readonly AssemblyTreeNode parentAssembly; readonly AssemblyTreeNode parentAssembly;

2
ILSpy/TypeTreeNode.cs

@ -27,7 +27,7 @@ using Mono.Cecil;
namespace ICSharpCode.ILSpy namespace ICSharpCode.ILSpy
{ {
sealed class TypeTreeNode : SharpTreeNode sealed class TypeTreeNode : ILSpyTreeNode
{ {
readonly TypeDefinition type; readonly TypeDefinition type;
readonly AssemblyTreeNode parentAssemblyNode; readonly AssemblyTreeNode parentAssemblyNode;

2
SharpTreeView/ExtensionMethods.cs

@ -12,7 +12,7 @@ using System.Windows.Input;
namespace ICSharpCode.TreeView namespace ICSharpCode.TreeView
{ {
public static class ExtensionMethods static class ExtensionMethods
{ {
public static T FindAncestor<T>(this DependencyObject d) where T : class public static T FindAncestor<T>(this DependencyObject d) where T : class
{ {

Loading…
Cancel
Save