Browse Source

New search.

pull/166/head
Daniel Grunwald 15 years ago
parent
commit
f5443a33d5
  1. 7
      ILSpy/AnalyzerTreeView.cs
  2. 2
      ILSpy/Controls/DockedPane.cs
  3. 112
      ILSpy/Controls/SearchBox.cs
  4. 6
      ILSpy/ILSpy.csproj
  5. 6
      ILSpy/Images/Images.cs
  6. 4
      ILSpy/LoadedAssembly.cs
  7. 22
      ILSpy/MainWindow.xaml
  8. 18
      ILSpy/MainWindow.xaml.cs
  9. 288
      ILSpy/SearchPane.cs
  10. 29
      ILSpy/SearchPane.xaml
  11. 3
      ILSpy/TreeNodes/EventTreeNode.cs
  12. 4
      ILSpy/TreeNodes/FieldTreeNode.cs

7
ILSpy/AnalyzerTreeView.cs

@ -34,7 +34,7 @@ namespace ICSharpCode.ILSpy @@ -34,7 +34,7 @@ namespace ICSharpCode.ILSpy
/// <summary>
/// Analyzer tree view.
/// </summary>
public partial class AnalyzerTreeView : SharpTreeView
public partial class AnalyzerTreeView : SharpTreeView, IPane
{
static AnalyzerTreeView instance;
@ -70,6 +70,11 @@ namespace ICSharpCode.ILSpy @@ -70,6 +70,11 @@ namespace ICSharpCode.ILSpy
this.SelectedItem = node;
this.FocusNode(node);
}
void IPane.Closed()
{
this.Root.Children.Clear();
}
}
[ExportMainMenuCommand(Menu = "_View", Header = "_Analyzer", MenuCategory = "ShowPane", MenuOrder = 100)]

2
ILSpy/Controls/DockedPane.cs

@ -68,7 +68,7 @@ namespace ICSharpCode.ILSpy.Controls @@ -68,7 +68,7 @@ namespace ICSharpCode.ILSpy.Controls
protected override void OnKeyDown(System.Windows.Input.KeyEventArgs e)
{
base.OnKeyDown(e);
if (!e.Handled && e.Key == Key.F4 && e.KeyboardDevice.Modifiers == ModifierKeys.Control) {
if (e.Key == Key.F4 && e.KeyboardDevice.Modifiers == ModifierKeys.Control || e.Key == Key.Escape) {
if (CloseButtonClicked != null)
CloseButtonClicked(this, e);
e.Handled = true;

112
ILSpy/Controls/SearchBox.cs

@ -28,10 +28,10 @@ namespace ICSharpCode.ILSpy.Controls @@ -28,10 +28,10 @@ namespace ICSharpCode.ILSpy.Controls
public class SearchBox : TextBox
{
static SearchBox() {
DefaultStyleKeyProperty.OverrideMetadata(
typeof(SearchBox),
new FrameworkPropertyMetadata(typeof(SearchBox)));
}
DefaultStyleKeyProperty.OverrideMetadata(
typeof(SearchBox),
new FrameworkPropertyMetadata(typeof(SearchBox)));
}
#region Dependency properties
@ -47,19 +47,19 @@ namespace ICSharpCode.ILSpy.Controls @@ -47,19 +47,19 @@ namespace ICSharpCode.ILSpy.Controls
#endregion
#region Public Properties
#region Public Properties
public string WatermarkText {
get { return (string)GetValue(WatermarkTextProperty); }
set { SetValue(WatermarkTextProperty, value); }
}
public string WatermarkText {
get { return (string)GetValue(WatermarkTextProperty); }
set { SetValue(WatermarkTextProperty, value); }
}
public Brush WatermarkColor {
get { return (Brush)GetValue(WatermarkColorProperty); }
set { SetValue(WatermarkColorProperty, value); }
}
public Brush WatermarkColor {
get { return (Brush)GetValue(WatermarkColorProperty); }
set { SetValue(WatermarkColorProperty, value); }
}
public bool HasText {
public bool HasText {
get { return (bool)GetValue(HasTextProperty); }
private set { SetValue(HasTextProperty, value); }
}
@ -69,49 +69,50 @@ namespace ICSharpCode.ILSpy.Controls @@ -69,49 +69,50 @@ namespace ICSharpCode.ILSpy.Controls
set { SetValue(UpdateDelayProperty, value); }
}
#endregion
#endregion
#region Handlers
#region Handlers
private void IconBorder_MouseLeftButtonUp(object obj, MouseButtonEventArgs e) {
if (this.HasText)
this.Text = string.Empty;
}
private void IconBorder_MouseLeftButtonUp(object obj, MouseButtonEventArgs e) {
if (this.HasText)
this.Text = string.Empty;
}
#endregion
#endregion
#region Overrides
#region Overrides
DispatcherTimer timer;
DispatcherTimer timer;
protected override void OnTextChanged(TextChangedEventArgs e) {
base.OnTextChanged(e);
protected override void OnTextChanged(TextChangedEventArgs e) {
base.OnTextChanged(e);
HasText = this.Text.Length > 0;
if (timer == null) {
timer = new DispatcherTimer();
timer.Tick += timer_Tick;
}
timer.Stop();
timer.Interval = this.UpdateDelay;
timer.Start();
}
HasText = this.Text.Length > 0;
if (timer == null) {
timer = new DispatcherTimer();
timer.Tick += timer_Tick;
}
timer.Stop();
timer.Interval = this.UpdateDelay;
timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{
timer.Stop();
timer = null;
var textBinding = GetBindingExpression(TextProperty);
if (textBinding != null) {
textBinding.UpdateSource();
}
}
void timer_Tick(object sender, EventArgs e)
{
timer.Stop();
timer = null;
var textBinding = GetBindingExpression(TextProperty);
if (textBinding != null) {
textBinding.UpdateSource();
}
}
protected override void OnLostFocus(RoutedEventArgs e)
{
if (!HasText) {
Label wl = (Label)GetTemplateChild("WatermarkLabel");
wl.Visibility = Visibility.Visible;
if (wl != null)
wl.Visibility = Visibility.Visible;
}
base.OnLostFocus(e);
@ -121,30 +122,31 @@ namespace ICSharpCode.ILSpy.Controls @@ -121,30 +122,31 @@ namespace ICSharpCode.ILSpy.Controls
{
if (!HasText) {
Label wl = (Label)GetTemplateChild("WatermarkLabel");
wl.Visibility = Visibility.Hidden;
if (wl != null)
wl.Visibility = Visibility.Hidden;
}
base.OnGotFocus(e);
}
public override void OnApplyTemplate() {
base.OnApplyTemplate();
public override void OnApplyTemplate() {
base.OnApplyTemplate();
Border iconBorder = GetTemplateChild("PART_IconBorder") as Border;
if (iconBorder != null) {
iconBorder.MouseLeftButtonUp += IconBorder_MouseLeftButtonUp;
}
}
Border iconBorder = GetTemplateChild("PART_IconBorder") as Border;
if (iconBorder != null) {
iconBorder.MouseLeftButtonUp += IconBorder_MouseLeftButtonUp;
}
}
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.Key == Key.Escape) {
if (e.Key == Key.Escape && this.Text.Length > 0) {
this.Text = string.Empty;
e.Handled = true;
} else {
base.OnKeyDown(e);
}
}
#endregion
#endregion
}
}

6
ILSpy/ILSpy.csproj

@ -135,6 +135,9 @@ @@ -135,6 +135,9 @@
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SearchPane.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="TreeNodes\Analyzer\AnalyzeContextMenuEntry.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedEventAccessorsTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedEventOverridesTreeNode.cs" />
@ -223,6 +226,9 @@ @@ -223,6 +226,9 @@
<Page Include="MainWindow.xaml" />
<Page Include="OpenFromGacDialog.xaml" />
<Page Include="OptionsDialog.xaml" />
<Page Include="SearchPane.xaml">
<DependentUpon>SearchPane.cs</DependentUpon>
</Page>
<Page Include="TextView\DecompilerTextView.xaml">
<DependentUpon>DecompilerTextView.cs</DependentUpon>
</Page>

6
ILSpy/Images/Images.cs

@ -112,12 +112,14 @@ namespace ICSharpCode.ILSpy @@ -112,12 +112,14 @@ namespace ICSharpCode.ILSpy
public static ImageSource GetIcon(TypeIcon icon, AccessOverlayIcon overlay)
{
return typeIconCache.GetIcon(icon, overlay, false);
lock (typeIconCache)
return typeIconCache.GetIcon(icon, overlay, false);
}
public static ImageSource GetIcon(MemberIcon icon, AccessOverlayIcon overlay, bool isStatic)
{
return memberIconCache.GetIcon(icon, overlay, isStatic);
lock (memberIconCache)
return memberIconCache.GetIcon(icon, overlay, isStatic);
}
#region icon caches & overlay management

4
ILSpy/LoadedAssembly.cs

@ -49,6 +49,10 @@ namespace ICSharpCode.ILSpy @@ -49,6 +49,10 @@ namespace ICSharpCode.ILSpy
this.shortName = Path.GetFileNameWithoutExtension(fileName);
}
/// <summary>
/// Gets the Cecil AssemblyDefinition.
/// Can be null when there was a load error.
/// </summary>
public AssemblyDefinition AssemblyDefinition {
get {
try {

22
ILSpy/MainWindow.xaml

@ -92,19 +92,13 @@ @@ -92,19 +92,13 @@
<RowDefinition
Height="*" />
</Grid.RowDefinitions>
<!-- Left pane: Search bar + Tree View -->
<DockPanel>
<!-- Search bar -->
<controls:SearchBox DockPanel.Dock="Top" WatermarkText="Search" WatermarkColor="Gray" ToolTip="Search"
Text="{Binding FilterSettings.SearchTerm}" />
<!-- Tree View of assemblies and classes -->
<tv:SharpTreeView
Name="treeView"
SelectionChanged="TreeView_SelectionChanged"
ShowRoot="False"
AllowDropOrder="True"
AllowDrop="True" />
</DockPanel>
<!-- Left pane: Tree View of assemblies and classes -->
<tv:SharpTreeView
Name="treeView"
SelectionChanged="TreeView_SelectionChanged"
ShowRoot="False"
AllowDropOrder="True"
AllowDrop="True" />
<GridSplitter
Grid.ZIndex="1"
Grid.Column="1"
@ -147,7 +141,7 @@ @@ -147,7 +141,7 @@
BorderBrush="Transparent"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Visibility="{Binding Visibility, ElementName=bottomPane}" />
Visibility="{Binding Visibility, ElementName=topPane}" />
<!-- decompilerTextView is into the mainPane by code -->
<ContentPresenter Name="mainPane" Grid.Row="3"/>

18
ILSpy/MainWindow.xaml.cs

@ -632,10 +632,6 @@ namespace ICSharpCode.ILSpy @@ -632,10 +632,6 @@ namespace ICSharpCode.ILSpy
topPane.Title = title;
topPane.Content = content;
topPane.Visibility = Visibility.Visible;
FrameworkElement fe = content as FrameworkElement;
if (fe != null)
fe.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
}
void TopPane_CloseButtonClicked(object sender, EventArgs e)
@ -644,6 +640,11 @@ namespace ICSharpCode.ILSpy @@ -644,6 +640,11 @@ namespace ICSharpCode.ILSpy
topPaneRow.MinHeight = 0;
topPaneRow.Height = new GridLength(0);
topPane.Visibility = Visibility.Collapsed;
IPane pane = topPane.Content as IPane;
topPane.Content = null;
if (pane != null)
pane.Closed();
}
public void ShowInBottomPane(string title, object content)
@ -656,10 +657,6 @@ namespace ICSharpCode.ILSpy @@ -656,10 +657,6 @@ namespace ICSharpCode.ILSpy
bottomPane.Title = title;
bottomPane.Content = content;
bottomPane.Visibility = Visibility.Visible;
FrameworkElement fe = content as FrameworkElement;
if (fe != null)
fe.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
}
void BottomPane_CloseButtonClicked(object sender, EventArgs e)
@ -668,6 +665,11 @@ namespace ICSharpCode.ILSpy @@ -668,6 +665,11 @@ namespace ICSharpCode.ILSpy
bottomPaneRow.MinHeight = 0;
bottomPaneRow.Height = new GridLength(0);
bottomPane.Visibility = Visibility.Collapsed;
IPane pane = bottomPane.Content as IPane;
bottomPane.Content = null;
if (pane != null)
pane.Closed();
}
#endregion
}

288
ILSpy/SearchPane.cs

@ -0,0 +1,288 @@ @@ -0,0 +1,288 @@
// 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.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading;
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.Threading;
using ICSharpCode.ILSpy.TreeNodes;
using Mono.Cecil;
namespace ICSharpCode.ILSpy
{
/// <summary>
/// Notifies panes when they are closed.
/// </summary>
public interface IPane
{
void Closed();
}
/// <summary>
/// Search pane
/// </summary>
public partial class SearchPane : UserControl, IPane
{
static SearchPane instance;
RunningSearch currentSearch;
public static SearchPane Instance {
get {
if (instance == null) {
App.Current.VerifyAccess();
instance = new SearchPane();
}
return instance;
}
}
private SearchPane()
{
InitializeComponent();
}
public void Show()
{
if (!IsVisible)
MainWindow.Instance.ShowInTopPane("Search", this);
Dispatcher.BeginInvoke(
DispatcherPriority.Background,
new Func<bool>(searchBox.Focus));
}
public static readonly DependencyProperty SearchTermProperty =
DependencyProperty.Register("SearchTerm", typeof(string), typeof(SearchPane),
new FrameworkPropertyMetadata(string.Empty, OnSearchTermChanged));
public string SearchTerm {
get { return (string)GetValue(SearchTermProperty); }
set { SetValue(SearchTermProperty, value); }
}
static void OnSearchTermChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
((SearchPane)o).StartSearch((string)e.NewValue);
}
void StartSearch(string searchTerm)
{
if (currentSearch != null) {
currentSearch.Cancel();
}
if (string.IsNullOrEmpty(searchTerm)) {
currentSearch = null;
listBox.ItemsSource = null;
} else {
MainWindow mainWindow = MainWindow.Instance;
currentSearch = new RunningSearch(mainWindow.CurrentAssemblyList.GetAssemblies(), searchTerm, mainWindow.CurrentLanguage);
listBox.ItemsSource = currentSearch.Results;
new Thread(currentSearch.Run).Start();
}
}
void IPane.Closed()
{
this.SearchTerm = string.Empty;
}
void ListBox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
JumpToSelectedItem();
e.Handled = true;
}
void ListBox_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Space || e.Key == Key.Return) {
e.Handled = true;
JumpToSelectedItem();
}
}
void JumpToSelectedItem()
{
SearchResult result = listBox.SelectedItem as SearchResult;
if (result != null) {
MainWindow.Instance.JumpToReference(result.Member);
}
}
}
sealed class RunningSearch
{
readonly Dispatcher dispatcher;
readonly CancellationTokenSource cts = new CancellationTokenSource();
readonly LoadedAssembly[] assemblies;
readonly string searchTerm;
readonly Language language;
public readonly ObservableCollection<SearchResult> Results = new ObservableCollection<SearchResult>();
int resultCount;
public RunningSearch(LoadedAssembly[] assemblies, string searchTerm, Language language)
{
this.dispatcher = Dispatcher.CurrentDispatcher;
this.assemblies = assemblies;
this.searchTerm = searchTerm;
this.language = language;
}
public void Cancel()
{
cts.Cancel();
}
public void Run()
{
try {
foreach (var loadedAssembly in assemblies) {
AssemblyDefinition asm = loadedAssembly.AssemblyDefinition;
if (asm == null)
continue;
CancellationToken cancellationToken = cts.Token;
foreach (TypeDefinition type in asm.MainModule.Types) {
cancellationToken.ThrowIfCancellationRequested();
PerformSearch(type);
}
}
} catch (OperationCanceledException) {
// ignore cancellation
}
}
void AddResult(SearchResult result)
{
if (++resultCount == 1000) {
result = new SearchResult { Name = "Search aborted, more than 1000 results found." };
cts.Cancel();
}
dispatcher.BeginInvoke(
DispatcherPriority.Normal,
new Action(delegate { this.Results.Add(result); }));
cts.Token.ThrowIfCancellationRequested();
}
bool IsMatch(string text)
{
if (text.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0)
return true;
else
return false;
}
void PerformSearch(TypeDefinition type)
{
if (IsMatch(type.Name)) {
AddResult(new SearchResult {
Member = type,
Image = TypeTreeNode.GetIcon(type),
Name = language.TypeToString(type, includeNamespace: false),
LocationImage = type.DeclaringType != null ? TypeTreeNode.GetIcon(type.DeclaringType) : Images.Namespace,
Location = type.DeclaringType != null ? language.TypeToString(type.DeclaringType, includeNamespace: true) : type.Namespace
});
}
foreach (TypeDefinition nestedType in type.NestedTypes) {
PerformSearch(nestedType);
}
foreach (FieldDefinition field in type.Fields) {
if (IsMatch(field.Name)) {
AddResult(new SearchResult {
Member = field,
Image = FieldTreeNode.GetIcon(field),
Name = field.Name,
LocationImage = TypeTreeNode.GetIcon(type),
Location = language.TypeToString(type, includeNamespace: true)
});
}
}
foreach (PropertyDefinition property in type.Properties) {
if (IsMatch(property.Name)) {
AddResult(new SearchResult {
Member = property,
Image = PropertyTreeNode.GetIcon(property),
Name = property.Name,
LocationImage = TypeTreeNode.GetIcon(type),
Location = language.TypeToString(type, includeNamespace: true)
});
}
}
foreach (EventDefinition ev in type.Events) {
if (IsMatch(ev.Name)) {
AddResult(new SearchResult {
Member = ev,
Image = EventTreeNode.GetIcon(ev),
Name = ev.Name,
LocationImage = TypeTreeNode.GetIcon(type),
Location = language.TypeToString(type, includeNamespace: true)
});
}
}
foreach (MethodDefinition method in type.Methods) {
if (IsMatch(method.Name)) {
AddResult(new SearchResult {
Member = method,
Image = MethodTreeNode.GetIcon(method),
Name = method.Name,
LocationImage = TypeTreeNode.GetIcon(type),
Location = language.TypeToString(type, includeNamespace: true)
});
}
}
}
}
class SearchResult : INotifyPropertyChanged
{
event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged {
add { }
remove { }
}
public MemberReference Member { get; set; }
public string Location { get; set; }
public string Name { get; set; }
public ImageSource Image { get; set; }
public ImageSource LocationImage { get; set; }
public override string ToString()
{
return Name;
}
}
[ExportMainMenuCommand(Menu = "_View", Header = "_Search", MenuIcon="Images/Find.png", MenuCategory = "ShowPane", MenuOrder = 100)]
sealed class ShowSearchCommand : SimpleCommand
{
public override void Execute(object parameter)
{
SearchPane.Instance.Show();
}
}
}

29
ILSpy/SearchPane.xaml

@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
<UserControl x:Class="ICSharpCode.ILSpy.SearchPane"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:ICSharpCode.ILSpy.Controls"
x:Name="self">
<DockPanel>
<controls:SearchBox DockPanel.Dock="Top" WatermarkText="Search" WatermarkColor="Gray" ToolTip="Search"
Text="{Binding SearchTerm, ElementName=self}" x:Name="searchBox" />
<ListBox Name="listBox" HorizontalContentAlignment="Stretch" SelectionMode="Single" MouseDoubleClick="ListBox_MouseDoubleClick" KeyDown="ListBox_KeyDown">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Width="16" Height="16" Source="{Binding Image}" HorizontalAlignment="Left" />
<TextBlock Text="{Binding Name}" Grid.Column="1" />
<StackPanel Orientation="Horizontal" Grid.Column="2" HorizontalAlignment="Right">
<Image Width="16" Height="16" Source="{Binding LocationImage}" Margin="4,0,4,0" />
<TextBlock Text="{Binding Location}" TextTrimming="CharacterEllipsis" />
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DockPanel>
</UserControl>

3
ILSpy/TreeNodes/EventTreeNode.cs

@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Windows.Media;
using ICSharpCode.Decompiler;
using Mono.Cecil;
@ -67,7 +68,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -67,7 +68,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
get { return GetIcon(ev); }
}
public static object GetIcon(EventDefinition eventDef)
public static ImageSource GetIcon(EventDefinition eventDef)
{
MethodDefinition accessor = eventDef.AddMethod ?? eventDef.RemoveMethod;
if (accessor != null)

4
ILSpy/TreeNodes/FieldTreeNode.cs

@ -76,10 +76,8 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -76,10 +76,8 @@ namespace ICSharpCode.ILSpy.TreeNodes
case FieldAttributes.Family:
case FieldAttributes.FamORAssem:
return AccessOverlayIcon.Protected;
case FieldAttributes.Private:
return AccessOverlayIcon.Private;
default:
throw new NotSupportedException();
return AccessOverlayIcon.Private;
}
}

Loading…
Cancel
Save