diff --git a/ILSpy/AvalonEdit/IconBarMargin.cs b/ILSpy/AvalonEdit/IconBarMargin.cs index f0f83848d..36ac3817a 100644 --- a/ILSpy/AvalonEdit/IconBarMargin.cs +++ b/ILSpy/AvalonEdit/IconBarMargin.cs @@ -32,6 +32,10 @@ namespace ICSharpCode.ILSpy.AvalonEdit this.manager = manager; } + public IconBarManager Manager { + get { return manager; } + } + public IList DecompiledMembers { get; set; } public virtual void Dispose() @@ -181,7 +185,7 @@ namespace ICSharpCode.ILSpy.AvalonEdit e.Handled = true; } - int GetLineFromMousePosition(MouseEventArgs e) + internal int GetLineFromMousePosition(MouseEventArgs e) { ICSharpCode.AvalonEdit.Rendering.TextView textView = this.TextView; if (textView == null) diff --git a/ILSpy/Bookmarks/BookmarkContextMenuEntry.cs b/ILSpy/Bookmarks/BookmarkContextMenuEntry.cs new file mode 100644 index 000000000..e47c4f68e --- /dev/null +++ b/ILSpy/Bookmarks/BookmarkContextMenuEntry.cs @@ -0,0 +1,189 @@ +// 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.ComponentModel.Composition; +using System.Linq; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows.Media; + +using ICSharpCode.ILSpy.AvalonEdit; + +namespace ICSharpCode.ILSpy.Bookmarks +{ + #region Context menu extensibility + public interface IBookmarkContextMenuEntry + { + bool IsVisible(IBookmark[] bookmarks); + bool IsEnabled(IBookmark[] bookmarks); + void Execute(IBookmark[] bookmarks); + } + + public interface IBookmarkContextMenuEntryMetadata + { + string Icon { get; } + string Header { get; } + string Category { get; } + + double Order { get; } + } + + [MetadataAttribute] + [AttributeUsage(AttributeTargets.Class, AllowMultiple=false)] + public class ExportBookmarkContextMenuEntryAttribute : ExportAttribute, IBookmarkContextMenuEntryMetadata + { + public ExportBookmarkContextMenuEntryAttribute() + : base(typeof(IBookmarkContextMenuEntry)) + { + } + + public string Icon { get; set; } + public string Header { get; set; } + public string Category { get; set; } + public double Order { get; set; } + } + #endregion + + #region Actions (simple clicks) - this will be used for creating bookmarks (e.g. Breakpoint bookmarks) + + public interface IBookmarkActionEntry + { + bool IsEnabled(); + void Execute(); + } + + public interface IBookmarkActionMetadata + { + string Category { get; } + + double Order { get; } + } + + [MetadataAttribute] + [AttributeUsage(AttributeTargets.Class, AllowMultiple=false)] + public class ExportBookmarkActionEntryAttribute : ExportAttribute, IBookmarkActionMetadata + { + public ExportBookmarkActionEntryAttribute() + : base(typeof(IBookmarkActionEntry)) + { + } + + public string Icon { get; set; } + public string Header { get; set; } + public string Category { get; set; } + public double Order { get; set; } + } + + #endregion + + internal class BookmarkContextMenuProvider + { + /// + /// Enables extensible context menu support for the specified tree view. + /// + public static void Add(IconBarMargin margin) + { + var provider = new BookmarkContextMenuProvider(margin); + margin.MouseDown += provider.MouseDown; + margin.ContextMenu = new ContextMenu(); + } + + readonly IconBarMargin margin; + + [ImportMany(typeof(IBookmarkContextMenuEntry))] + Lazy[] contextEntries = null; + + [ImportMany(typeof(IBookmarkActionEntry))] + Lazy[] actionEntries = null; + + private BookmarkContextMenuProvider(IconBarMargin margin) + { + this.margin = margin; + App.CompositionContainer.ComposeParts(this); + } + + void MouseDown(object sender, MouseButtonEventArgs e) + { + int line = margin.GetLineFromMousePosition(e); + + var bookmarks = margin.Manager.Bookmarks.ToArray(); + if (bookmarks.Length == 0) { + // don't show the menu + e.Handled = true; + this.margin.ContextMenu = null; + return; + } + + if (e.LeftButton == MouseButtonState.Pressed) { + foreach (var category in actionEntries.OrderBy(c => c.Metadata.Order).GroupBy(c => c.Metadata.Category)) { + foreach (var entryPair in category) { + IBookmarkActionEntry entry = entryPair.Value; + + if (entryPair.Value.IsEnabled()) { + entry.Execute(); + } + } + } + } + + if (e.RightButton == MouseButtonState.Pressed) { + // check if we are on a Member + var bookmark = bookmarks.FirstOrDefault(b => b.LineNumber == line); + if (bookmark == null) { + // don't show the menu + e.Handled = true; + this.margin.ContextMenu = null; + return; + } + + var marks = new[] { bookmark }; + ContextMenu menu = new ContextMenu(); + foreach (var category in contextEntries.OrderBy(c => c.Metadata.Order).GroupBy(c => c.Metadata.Category)) { + if (menu.Items.Count > 0) { + menu.Items.Add(new Separator()); + } + foreach (var entryPair in category) { + IBookmarkContextMenuEntry entry = entryPair.Value; + if (entry.IsVisible(marks)) { + MenuItem menuItem = new MenuItem(); + menuItem.Header = entryPair.Metadata.Header; + if (!string.IsNullOrEmpty(entryPair.Metadata.Icon)) { + menuItem.Icon = new Image { + Width = 16, + Height = 16, + Source = Images.LoadImage(entry, entryPair.Metadata.Icon) + }; + } + if (entryPair.Value.IsEnabled(marks)) { + menuItem.Click += delegate { entry.Execute(marks); }; + } else + menuItem.IsEnabled = false; + menu.Items.Add(menuItem); + } + } + } + if (menu.Items.Count > 0) + margin.ContextMenu = menu; + else + // hide the context menu. + e.Handled = true; + } + } + } +} diff --git a/ILSpy/Bookmarks/Commands.cs b/ILSpy/Bookmarks/Commands.cs new file mode 100644 index 000000000..40d71eef0 --- /dev/null +++ b/ILSpy/Bookmarks/Commands.cs @@ -0,0 +1,63 @@ +// 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 ICSharpCode.ILSpy.TreeNodes.Analyzer; +using Mono.Cecil; + +namespace ICSharpCode.ILSpy.Bookmarks +{ + [ExportBookmarkContextMenuEntry(Header = "Analyze", Icon = "images/Search.png", Category="Default")] + internal sealed class AnalyzeBookmarkEntry : IBookmarkContextMenuEntry + { + public bool IsVisible(IBookmark[] marks) + { + return true; + } + + public bool IsEnabled(IBookmark[] marks) + { + return true; + } + + public void Execute(IBookmark[] marks) + { + foreach (var node in marks) { + if (!(node is MemberBookmark)) + continue; + + var member = (node as MemberBookmark).Node.Annotation(); + TypeDefinition type = member as TypeDefinition; + if (type != null) + AnalyzerTreeView.Instance.Show(new AnalyzedTypeTreeNode(type)); + FieldDefinition field = member as FieldDefinition; + if (field != null) + AnalyzerTreeView.Instance.Show(new AnalyzedFieldTreeNode(field)); + MethodDefinition method = member as MethodDefinition; + if (method != null) + AnalyzerTreeView.Instance.Show(new AnalyzedMethodTreeNode(method)); + var propertyAnalyzer = AnalyzedPropertyTreeNode.TryCreateAnalyzer(member); + if (propertyAnalyzer != null) + AnalyzerTreeView.Instance.Show(propertyAnalyzer); + var eventAnalyzer = AnalyzedEventTreeNode.TryCreateAnalyzer(member); + if (eventAnalyzer != null) + AnalyzerTreeView.Instance.Show(eventAnalyzer); + } + } + } +} diff --git a/ILSpy/Bookmarks/MemberBookmark.cs b/ILSpy/Bookmarks/MemberBookmark.cs index fb8b2ec3b..9a0996095 100644 --- a/ILSpy/Bookmarks/MemberBookmark.cs +++ b/ILSpy/Bookmarks/MemberBookmark.cs @@ -82,9 +82,6 @@ namespace ICSharpCode.ILSpy.Bookmarks public virtual void MouseDown(MouseButtonEventArgs e) { - if (e.ChangedButton == MouseButton.Left) { - // TODO: menu items - } } public virtual void MouseUp(MouseButtonEventArgs e) @@ -137,17 +134,6 @@ namespace ICSharpCode.ILSpy.Bookmarks } } - public override void MouseDown(MouseButtonEventArgs e) - { - if (e.ChangedButton == MouseButton.Left) { - // TODO: menu items - } - } - - public override void MouseUp(MouseButtonEventArgs e) - { - } - ImageSource GetTypeOverlayedImage(AttributedNode attrNode, TypeIcon icon) { switch (attrNode.Modifiers & Modifiers.VisibilityMask) { diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index 8452df456..7579f9c05 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -100,8 +100,10 @@ + + diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs index 2d355e006..66028707d 100644 --- a/ILSpy/TextView/DecompilerTextView.cs +++ b/ILSpy/TextView/DecompilerTextView.cs @@ -42,6 +42,7 @@ using ICSharpCode.AvalonEdit.Highlighting.Xshd; using ICSharpCode.AvalonEdit.Rendering; using ICSharpCode.Decompiler; using ICSharpCode.ILSpy.AvalonEdit; +using ICSharpCode.ILSpy.Bookmarks; using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.XmlDoc; using ICSharpCode.NRefactory.Documentation; @@ -101,6 +102,9 @@ namespace ICSharpCode.ILSpy.TextView textEditor.TextArea.LeftMargins.Add(iconMargin); textEditor.TextArea.TextView.VisualLinesChanged += delegate { iconMargin.InvalidateVisual(); }; + + // Bookmarks context menu + BookmarkContextMenuProvider.Add(iconMargin); } #endregion