From d0670aae7bfda831e7809793743bc601307e6c72 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sat, 5 Mar 2011 00:48:40 +0100 Subject: [PATCH] Use MEF for the existing File menu items. --- ILSpy/AboutPage.cs | 2 +- ILSpy/AssemblyList.cs | 4 +- ILSpy/Commands.cs | 55 +++++++++++++++++++++--- ILSpy/ExportCommandAttribute.cs | 24 +++++------ ILSpy/LoadedAssembly.cs | 2 +- ILSpy/MainWindow.xaml | 20 +-------- ILSpy/MainWindow.xaml.cs | 62 +++++++++++++--------------- ILSpy/TreeNodes/AssemblyTreeNode.cs | 2 +- ILSpy/TreeNodes/EventTreeNode.cs | 2 +- ILSpy/TreeNodes/FieldTreeNode.cs | 2 +- ILSpy/TreeNodes/MethodTreeNode.cs | 2 +- ILSpy/TreeNodes/NamespaceTreeNode.cs | 2 +- ILSpy/TreeNodes/PropertyTreeNode.cs | 2 +- ILSpy/TreeNodes/TypeTreeNode.cs | 2 +- 14 files changed, 103 insertions(+), 80 deletions(-) diff --git a/ILSpy/AboutPage.cs b/ILSpy/AboutPage.cs index 92114b5ee..4eb58209d 100644 --- a/ILSpy/AboutPage.cs +++ b/ILSpy/AboutPage.cs @@ -21,7 +21,7 @@ using ICSharpCode.ILSpy.TextView; namespace ICSharpCode.ILSpy { - [ExportMainMenuCommand(Menu = "_Help", Header = "_About", Order = 99999)] + [ExportMainMenuCommand(Menu = "_Help", Header = "_About", MenuOrder = 99999)] sealed class AboutPage : SimpleCommand { [Import] diff --git a/ILSpy/AssemblyList.cs b/ILSpy/AssemblyList.cs index 7fa82293b..336d7c4f3 100644 --- a/ILSpy/AssemblyList.cs +++ b/ILSpy/AssemblyList.cs @@ -32,7 +32,7 @@ namespace ICSharpCode.ILSpy /// /// A list of assemblies. /// - sealed class AssemblyList + public sealed class AssemblyList { readonly string listName; @@ -81,7 +81,7 @@ namespace ICSharpCode.ILSpy /// /// Saves this assembly list to XML. /// - public XElement SaveAsXml() + internal XElement SaveAsXml() { return new XElement( "List", diff --git a/ILSpy/Commands.cs b/ILSpy/Commands.cs index 78b153a1e..462fa1602 100644 --- a/ILSpy/Commands.cs +++ b/ILSpy/Commands.cs @@ -2,11 +2,16 @@ // This code is distributed under MIT X11 license (for details please see \doc\license.txt) using System; +using System.ComponentModel.Composition; +using System.Linq; using System.Windows.Input; +using ICSharpCode.ILSpy.TextView; +using ICSharpCode.ILSpy.TreeNodes; + namespace ICSharpCode.ILSpy { - [ExportMainMenuCommand(Menu = "_File", Header = "E_xit", Order = 99999, Category = "Exit")] + [ExportMainMenuCommand(Menu = "_File", Header = "E_xit", MenuOrder = 99999, MenuCategory = "Exit")] sealed class ExitCommand : SimpleCommand { public override void Execute(object parameter) @@ -15,26 +20,57 @@ namespace ICSharpCode.ILSpy } } - [ExportToolbarCommand(ToolTip = "Back", Icon = "Images/Back.png", Category = "Navigation")] + [ExportToolbarCommand(ToolTip = "Back", ToolbarIcon = "Images/Back.png", ToolbarCategory = "Navigation", ToolbarOrder = 0)] sealed class BrowseBackCommand : CommandWrapper { public BrowseBackCommand() : base(NavigationCommands.BrowseBack) {} } - [ExportToolbarCommand(ToolTip = "Forward", Icon = "Images/Forward.png", Category = "Navigation", Order = 1)] + [ExportToolbarCommand(ToolTip = "Forward", ToolbarIcon = "Images/Forward.png", ToolbarCategory = "Navigation", ToolbarOrder = 1)] sealed class BrowseForwardCommand : CommandWrapper { public BrowseForwardCommand() : base(NavigationCommands.BrowseForward) {} } - [ExportToolbarCommand(ToolTip = "Open", Icon = "Images/Open.png", Category = "Open")] + [ExportToolbarCommand(ToolTip = "Open", ToolbarIcon = "Images/Open.png", ToolbarCategory = "Open", ToolbarOrder = 0)] + [ExportMainMenuCommand(Menu = "_File", MenuIcon = "Images/Open.png", MenuCategory = "Open", MenuOrder = 0)] sealed class OpenCommand : CommandWrapper { public OpenCommand() : base(ApplicationCommands.Open) {} } - [ExportToolbarCommand(ToolTip = "Reload all assemblies", Icon = "Images/Refresh.png", Category = "Open", Order = 1)] + [ExportMainMenuCommand(Menu = "_File", Header = "Open from _GAC", MenuCategory = "Open", MenuOrder = 1)] + sealed class OpenFromGacCommand : SimpleCommand + { + public override void Execute(object parameter) + { + OpenFromGacDialog dlg = new OpenFromGacDialog(); + dlg.Owner = MainWindow.Instance; + if (dlg.ShowDialog() == true) { + MainWindow.Instance.OpenFiles(dlg.SelectedFileNames); + } + } + } + + [ExportToolbarCommand(ToolTip = "Reload all assemblies", ToolbarIcon = "Images/Refresh.png", ToolbarCategory = "Open", ToolbarOrder = 2)] + [ExportMainMenuCommand(Menu = "_File", Header = "Reload", MenuIcon = "Images/Refresh.png", MenuCategory = "Open", MenuOrder = 2)] sealed class RefreshCommand : CommandWrapper { public RefreshCommand() : base(NavigationCommands.Refresh) {} } + [ExportMainMenuCommand(Menu = "_File", Header = "_Save Code...", MenuIcon = "Images/SaveFile.png", MenuCategory = "Save", MenuOrder = 0)] + sealed class SaveCommand : SimpleCommand + { + public override void Execute(object parameter) + { + MainWindow mainWindow = MainWindow.Instance; + if (mainWindow.SelectedNodes.Count() == 1) { + if (mainWindow.SelectedNodes.Single().Save(mainWindow.TextView)) + return; + } + mainWindow.TextView.SaveToDisk(mainWindow.CurrentLanguage, + mainWindow.SelectedNodes, + new DecompilationOptions() { FullDecompilation = true }); + } + } + class CommandWrapper : ICommand { ICommand wrappedCommand; @@ -44,6 +80,15 @@ namespace ICSharpCode.ILSpy this.wrappedCommand = wrappedCommand; } + public static ICommand Unwrap(ICommand command) + { + CommandWrapper w = command as CommandWrapper; + if (w != null) + return w.wrappedCommand; + else + return command; + } + public event EventHandler CanExecuteChanged { add { wrappedCommand.CanExecuteChanged += value; } remove { wrappedCommand.CanExecuteChanged -= value; } diff --git a/ILSpy/ExportCommandAttribute.cs b/ILSpy/ExportCommandAttribute.cs index 12eab3f45..b83fd698f 100644 --- a/ILSpy/ExportCommandAttribute.cs +++ b/ILSpy/ExportCommandAttribute.cs @@ -10,11 +10,11 @@ namespace ICSharpCode.ILSpy #region Toolbar public interface IToolbarCommandMetadata { - string Icon { get; } + string ToolbarIcon { get; } string ToolTip { get; } - string Category { get; } + string ToolbarCategory { get; } - double Order { get; } + double ToolbarOrder { get; } } [MetadataAttribute] @@ -27,21 +27,21 @@ namespace ICSharpCode.ILSpy } public string ToolTip { get; set; } - public string Icon { get; set; } - public string Category { get; set; } - public double Order { get; set; } + public string ToolbarIcon { get; set; } + public string ToolbarCategory { get; set; } + public double ToolbarOrder { get; set; } } #endregion #region Main Menu public interface IMainMenuCommandMetadata { - string Icon { get; } + string MenuIcon { get; } string Header { get; } string Menu { get; } - string Category { get; } + string MenuCategory { get; } - double Order { get; } + double MenuOrder { get; } } [MetadataAttribute] @@ -53,11 +53,11 @@ namespace ICSharpCode.ILSpy { } - public string Icon { get; set; } + public string MenuIcon { get; set; } public string Header { get; set; } public string Menu { get; set; } - public string Category { get; set; } - public double Order { get; set; } + public string MenuCategory { get; set; } + public double MenuOrder { get; set; } } #endregion } diff --git a/ILSpy/LoadedAssembly.cs b/ILSpy/LoadedAssembly.cs index 6e9752b1b..81f46e142 100644 --- a/ILSpy/LoadedAssembly.cs +++ b/ILSpy/LoadedAssembly.cs @@ -14,7 +14,7 @@ namespace ICSharpCode.ILSpy /// /// Represents an assembly loaded into ILSpy. /// - sealed class LoadedAssembly + public sealed class LoadedAssembly { readonly Task assemblyTask; readonly AssemblyList assemblyList; diff --git a/ILSpy/MainWindow.xaml b/ILSpy/MainWindow.xaml index bf18485d7..8a4fc3783 100644 --- a/ILSpy/MainWindow.xaml +++ b/ILSpy/MainWindow.xaml @@ -34,25 +34,7 @@ - - - - - - - - - - - - - - - - - - - + diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs index 4f2515420..5056a19a9 100644 --- a/ILSpy/MainWindow.xaml.cs +++ b/ILSpy/MainWindow.xaml.cs @@ -107,7 +107,7 @@ namespace ICSharpCode.ILSpy { int navigationPos = 0; int openPos = 1; - foreach (var commandGroup in toolbarCommands.OrderBy(c => c.Metadata.Order).GroupBy(c => c.Metadata.Category)) { + foreach (var commandGroup in toolbarCommands.OrderBy(c => c.Metadata.ToolbarOrder).GroupBy(c => c.Metadata.ToolbarCategory)) { if (commandGroup.Key == "Navigation") { foreach (var command in commandGroup) { toolBar.Items.Insert(navigationPos++, MakeToolbarItem(command)); @@ -130,12 +130,12 @@ namespace ICSharpCode.ILSpy Button MakeToolbarItem(Lazy command) { return new Button { - Command = command.Value, + Command = CommandWrapper.Unwrap(command.Value), ToolTip = command.Metadata.ToolTip, Content = new Image { Width = 16, Height = 16, - Source = Images.LoadImage(command.Value, command.Metadata.Icon) + Source = Images.LoadImage(command.Value, command.Metadata.ToolbarIcon) } }; } @@ -147,25 +147,26 @@ namespace ICSharpCode.ILSpy void InitMainMenu() { - foreach (var topLevelMenu in mainMenuCommands.OrderBy(c => c.Metadata.Order).GroupBy(c => c.Metadata.Menu)) { + foreach (var topLevelMenu in mainMenuCommands.OrderBy(c => c.Metadata.MenuOrder).GroupBy(c => c.Metadata.Menu)) { var topLevelMenuItem = mainMenu.Items.OfType().FirstOrDefault(m => (m.Header as string) == topLevelMenu.Key); - foreach (var category in topLevelMenu.GroupBy(c => c.Metadata.Category)) { + foreach (var category in topLevelMenu.GroupBy(c => c.Metadata.MenuCategory)) { if (topLevelMenuItem == null) { topLevelMenuItem = new MenuItem(); topLevelMenuItem.Header = topLevelMenu.Key; mainMenu.Items.Add(topLevelMenuItem); - } else { + } else if (topLevelMenuItem.Items.Count > 0) { topLevelMenuItem.Items.Add(new Separator()); } foreach (var entry in category) { MenuItem menuItem = new MenuItem(); - menuItem.Header = entry.Metadata.Header; - menuItem.Command = entry.Value; - if (!string.IsNullOrEmpty(entry.Metadata.Icon)) { + menuItem.Command = CommandWrapper.Unwrap(entry.Value); + if (!string.IsNullOrEmpty(entry.Metadata.Header)) + menuItem.Header = entry.Metadata.Header; + if (!string.IsNullOrEmpty(entry.Metadata.MenuIcon)) { menuItem.Icon = new Image { Width = 16, Height = 16, - Source = Images.LoadImage(entry.Value, entry.Metadata.Icon) + Source = Images.LoadImage(entry.Value, entry.Metadata.MenuIcon) }; } topLevelMenuItem.Items.Add(menuItem); @@ -388,8 +389,10 @@ namespace ICSharpCode.ILSpy } } - void OpenFiles(string[] fileNames) + public void OpenFiles(string[] fileNames) { + if (fileNames == null) + throw new ArgumentNullException("fileNames"); treeView.UnselectAll(); SharpTreeNode lastNode = null; foreach (string file in fileNames) { @@ -413,18 +416,9 @@ namespace ICSharpCode.ILSpy ShowAssemblyList(assemblyListManager.LoadList(ILSpySettings.Load(), assemblyList.ListName)); SelectNode(FindNodeByPath(path, true)); } - - void OpenFromGac_Click(object sender, RoutedEventArgs e) - { - OpenFromGacDialog dlg = new OpenFromGacDialog(); - dlg.Owner = this; - if (dlg.ShowDialog() == true) { - OpenFiles(dlg.SelectedFileNames); - } - } #endregion - #region Decompile / Save + #region Decompile (TreeView_SelectionChanged) void TreeView_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (treeView.SelectedItems.Count == 1) { @@ -432,21 +426,23 @@ namespace ICSharpCode.ILSpy if (node != null && node.View(decompilerTextView)) return; } - decompilerTextView.Decompile(sessionSettings.FilterSettings.Language, - treeView.GetTopLevelSelection().OfType(), - new DecompilationOptions()); + decompilerTextView.Decompile(this.CurrentLanguage, this.SelectedNodes, new DecompilationOptions()); } - void saveCode_Click(object sender, RoutedEventArgs e) - { - if (treeView.SelectedItems.Count == 1) { - ILSpyTreeNode node = treeView.SelectedItem as ILSpyTreeNode; - if (node != null && node.Save(decompilerTextView)) - return; + public DecompilerTextView TextView { + get { return decompilerTextView; } + } + + public Language CurrentLanguage { + get { + return sessionSettings.FilterSettings.Language; + } + } + + public IEnumerable SelectedNodes { + get { + return treeView.GetTopLevelSelection().OfType(); } - decompilerTextView.SaveToDisk(sessionSettings.FilterSettings.Language, - treeView.GetTopLevelSelection().OfType(), - new DecompilationOptions() { FullDecompilation = true }); } #endregion diff --git a/ILSpy/TreeNodes/AssemblyTreeNode.cs b/ILSpy/TreeNodes/AssemblyTreeNode.cs index 35865ef2d..1123ee219 100644 --- a/ILSpy/TreeNodes/AssemblyTreeNode.cs +++ b/ILSpy/TreeNodes/AssemblyTreeNode.cs @@ -38,7 +38,7 @@ namespace ICSharpCode.ILSpy.TreeNodes /// Tree node representing an assembly. /// This class is responsible for loading both namespace and type nodes. /// - sealed class AssemblyTreeNode : ILSpyTreeNode + public sealed class AssemblyTreeNode : ILSpyTreeNode { readonly LoadedAssembly assembly; readonly List classes = new List(); diff --git a/ILSpy/TreeNodes/EventTreeNode.cs b/ILSpy/TreeNodes/EventTreeNode.cs index 9d75b5215..deed40194 100644 --- a/ILSpy/TreeNodes/EventTreeNode.cs +++ b/ILSpy/TreeNodes/EventTreeNode.cs @@ -25,7 +25,7 @@ namespace ICSharpCode.ILSpy.TreeNodes /// /// Represents an event in the TreeView. /// - sealed class EventTreeNode : ILSpyTreeNode + public sealed class EventTreeNode : ILSpyTreeNode { readonly EventDefinition ev; diff --git a/ILSpy/TreeNodes/FieldTreeNode.cs b/ILSpy/TreeNodes/FieldTreeNode.cs index d3becb0ce..91f7f31cb 100644 --- a/ILSpy/TreeNodes/FieldTreeNode.cs +++ b/ILSpy/TreeNodes/FieldTreeNode.cs @@ -27,7 +27,7 @@ namespace ICSharpCode.ILSpy.TreeNodes /// /// Represents a field in the TreeView. /// - sealed class FieldTreeNode : ILSpyTreeNode + public sealed class FieldTreeNode : ILSpyTreeNode { readonly FieldDefinition field; diff --git a/ILSpy/TreeNodes/MethodTreeNode.cs b/ILSpy/TreeNodes/MethodTreeNode.cs index 7c015d5fd..9f7898dbc 100644 --- a/ILSpy/TreeNodes/MethodTreeNode.cs +++ b/ILSpy/TreeNodes/MethodTreeNode.cs @@ -29,7 +29,7 @@ namespace ICSharpCode.ILSpy.TreeNodes /// /// Tree Node representing a field, method, property, or event. /// - sealed class MethodTreeNode : ILSpyTreeNode + public sealed class MethodTreeNode : ILSpyTreeNode { MethodDefinition method; diff --git a/ILSpy/TreeNodes/NamespaceTreeNode.cs b/ILSpy/TreeNodes/NamespaceTreeNode.cs index 69810d852..054b4bf74 100644 --- a/ILSpy/TreeNodes/NamespaceTreeNode.cs +++ b/ILSpy/TreeNodes/NamespaceTreeNode.cs @@ -25,7 +25,7 @@ namespace ICSharpCode.ILSpy.TreeNodes /// /// Namespace node. The loading of the type nodes is handled by the parent AssemblyTreeNode. /// - sealed class NamespaceTreeNode : ILSpyTreeNode + public sealed class NamespaceTreeNode : ILSpyTreeNode { string name; diff --git a/ILSpy/TreeNodes/PropertyTreeNode.cs b/ILSpy/TreeNodes/PropertyTreeNode.cs index b815524ca..340ac9f9b 100644 --- a/ILSpy/TreeNodes/PropertyTreeNode.cs +++ b/ILSpy/TreeNodes/PropertyTreeNode.cs @@ -25,7 +25,7 @@ namespace ICSharpCode.ILSpy.TreeNodes /// /// Represents a property in the TreeView. /// - sealed class PropertyTreeNode : ILSpyTreeNode + public sealed class PropertyTreeNode : ILSpyTreeNode { readonly PropertyDefinition property; readonly bool isIndexer; diff --git a/ILSpy/TreeNodes/TypeTreeNode.cs b/ILSpy/TreeNodes/TypeTreeNode.cs index c7b39a7c0..558511589 100644 --- a/ILSpy/TreeNodes/TypeTreeNode.cs +++ b/ILSpy/TreeNodes/TypeTreeNode.cs @@ -26,7 +26,7 @@ using Mono.Cecil; namespace ICSharpCode.ILSpy.TreeNodes { - sealed class TypeTreeNode : ILSpyTreeNode + public sealed class TypeTreeNode : ILSpyTreeNode { readonly TypeDefinition type; readonly AssemblyTreeNode parentAssemblyNode;