From 56b9401a49e8306fea541f9e8d805afec91ca610 Mon Sep 17 00:00:00 2001 From: Andreas Weizel Date: Fri, 11 Oct 2019 21:13:05 +0200 Subject: [PATCH 01/12] Basic work to add AvalonDock using MVVM, avoiding too big changes to existing architecture for now --- ILSpy/Analyzers/AnalyzeCommand.cs | 16 +-- ILSpy/Analyzers/AnalyzerTreeView.cs | 21 +-- ILSpy/Commands/DecompileInNewViewCommand.cs | 5 +- ILSpy/Commands/ShowDebugSteps.cs | 4 +- ILSpy/DebugSteps.xaml.cs | 6 +- ILSpy/Docking/ActiveDocumentConverter.cs | 25 ++++ ILSpy/Docking/DockLayoutSettings.cs | 2 +- ILSpy/Docking/DockWorkspace.cs | 47 +++++++ ILSpy/Docking/DockingHelper.cs | 50 ++++++- ILSpy/Docking/LayoutUpdateStrategy.cs | 42 ++++++ ILSpy/Docking/PaneCollection.cs | 43 ++++++ ILSpy/Docking/PanePosition.cs | 2 + ILSpy/Docking/PaneStyleSelector.cs | 24 ++++ ILSpy/Docking/PaneTemplateSelector.cs | 25 ++++ ILSpy/ILSpy.csproj | 13 ++ ILSpy/MainWindow.xaml | 140 ++++++++++++++------ ILSpy/MainWindow.xaml.cs | 78 ++++++++--- ILSpy/Search/SearchPane.cs | 17 +-- ILSpy/ViewModels/AnalyzerPaneModel.cs | 15 +++ ILSpy/ViewModels/AssemblyListPaneModel.cs | 16 +++ ILSpy/ViewModels/DebugStepsPaneModel.cs | 15 +++ ILSpy/ViewModels/DocumentModel.cs | 12 ++ ILSpy/ViewModels/PaneModel.cs | 80 +++++++++++ ILSpy/ViewModels/SearchPaneModel.cs | 16 +++ ILSpy/ViewModels/ToolPaneModel.cs | 7 + 25 files changed, 616 insertions(+), 105 deletions(-) create mode 100644 ILSpy/Docking/ActiveDocumentConverter.cs create mode 100644 ILSpy/Docking/DockWorkspace.cs create mode 100644 ILSpy/Docking/LayoutUpdateStrategy.cs create mode 100644 ILSpy/Docking/PaneCollection.cs create mode 100644 ILSpy/Docking/PaneStyleSelector.cs create mode 100644 ILSpy/Docking/PaneTemplateSelector.cs create mode 100644 ILSpy/ViewModels/AnalyzerPaneModel.cs create mode 100644 ILSpy/ViewModels/AssemblyListPaneModel.cs create mode 100644 ILSpy/ViewModels/DebugStepsPaneModel.cs create mode 100644 ILSpy/ViewModels/DocumentModel.cs create mode 100644 ILSpy/ViewModels/PaneModel.cs create mode 100644 ILSpy/ViewModels/SearchPaneModel.cs create mode 100644 ILSpy/ViewModels/ToolPaneModel.cs diff --git a/ILSpy/Analyzers/AnalyzeCommand.cs b/ILSpy/Analyzers/AnalyzeCommand.cs index 3d8ae667c..35ae8a987 100644 --- a/ILSpy/Analyzers/AnalyzeCommand.cs +++ b/ILSpy/Analyzers/AnalyzeCommand.cs @@ -58,17 +58,17 @@ namespace ICSharpCode.ILSpy.Analyzers { if (context.SelectedTreeNodes != null) { foreach (IMemberTreeNode node in context.SelectedTreeNodes) { - AnalyzerTreeView.Instance.Analyze(node.Member); + MainWindow.Instance.AnalyzerTreeView.Analyze(node.Member); } } else if (context.Reference != null && context.Reference.Reference is IEntity entity) { - AnalyzerTreeView.Instance.Analyze(entity); + MainWindow.Instance.AnalyzerTreeView.Analyze(entity); } } public override bool CanExecute(object parameter) { - if (AnalyzerTreeView.Instance.IsKeyboardFocusWithin) { - return AnalyzerTreeView.Instance.SelectedItems.OfType().All(n => n is IMemberTreeNode); + if (MainWindow.Instance.AnalyzerTreeView.IsKeyboardFocusWithin) { + return MainWindow.Instance.AnalyzerTreeView.SelectedItems.OfType().All(n => n is IMemberTreeNode); } else { return MainWindow.Instance.SelectedNodes.All(n => n is IMemberTreeNode); } @@ -76,13 +76,13 @@ namespace ICSharpCode.ILSpy.Analyzers public override void Execute(object parameter) { - if (AnalyzerTreeView.Instance.IsKeyboardFocusWithin) { - foreach (IMemberTreeNode node in AnalyzerTreeView.Instance.SelectedItems.OfType().ToArray()) { - AnalyzerTreeView.Instance.Analyze(node.Member); + if (MainWindow.Instance.AnalyzerTreeView.IsKeyboardFocusWithin) { + foreach (IMemberTreeNode node in MainWindow.Instance.AnalyzerTreeView.SelectedItems.OfType().ToArray()) { + MainWindow.Instance.AnalyzerTreeView.Analyze(node.Member); } } else { foreach (IMemberTreeNode node in MainWindow.Instance.SelectedNodes) { - AnalyzerTreeView.Instance.Analyze(node.Member); + MainWindow.Instance.AnalyzerTreeView.Analyze(node.Member); } } } diff --git a/ILSpy/Analyzers/AnalyzerTreeView.cs b/ILSpy/Analyzers/AnalyzerTreeView.cs index 13b29bd3f..2a8bb2fa1 100644 --- a/ILSpy/Analyzers/AnalyzerTreeView.cs +++ b/ILSpy/Analyzers/AnalyzerTreeView.cs @@ -23,6 +23,8 @@ using System.Linq; using System.Windows; using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.ILSpy.Analyzers.TreeNodes; +using ICSharpCode.ILSpy.Docking; +using ICSharpCode.ILSpy.ViewModels; using ICSharpCode.TreeView; namespace ICSharpCode.ILSpy.Analyzers @@ -32,21 +34,7 @@ namespace ICSharpCode.ILSpy.Analyzers /// public class AnalyzerTreeView : SharpTreeView, IPane { - static AnalyzerTreeView instance; - - public static AnalyzerTreeView Instance - { - get - { - if (instance == null) { - App.Current.VerifyAccess(); - instance = new AnalyzerTreeView(); - } - return instance; - } - } - - private AnalyzerTreeView() + public AnalyzerTreeView() { this.ShowRoot = false; this.Root = new AnalyzerRootNode { Language = MainWindow.Instance.CurrentLanguage }; @@ -72,8 +60,7 @@ namespace ICSharpCode.ILSpy.Analyzers public void Show() { - if (!IsVisible) - MainWindow.Instance.ShowInNewPane("Analyzer", this, PanePosition.Bottom); + DockWorkspace.Instance.ToolPanes.Add(AnalyzerPaneModel.Instance); } public void Show(AnalyzerTreeNode node) diff --git a/ILSpy/Commands/DecompileInNewViewCommand.cs b/ILSpy/Commands/DecompileInNewViewCommand.cs index 3b335743d..2a1119fe3 100644 --- a/ILSpy/Commands/DecompileInNewViewCommand.cs +++ b/ILSpy/Commands/DecompileInNewViewCommand.cs @@ -17,6 +17,7 @@ // DEALINGS IN THE SOFTWARE. using System.Linq; +using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TreeNodes; @@ -45,7 +46,9 @@ namespace ICSharpCode.ILSpy.Commands var dtv = new DecompilerTextView(); var nodes = context.SelectedTreeNodes.Cast().ToArray(); var title = string.Join(", ", nodes.Select(x => x.ToString())); - MainWindow.Instance.ShowInNewPane(title, dtv, PanePosition.Document); + // TODO + //MainWindow.Instance.ShowInNewPane(title, dtv, PanePosition.Document); + //DockWorkspace.Instance.Documents.Add(new ViewModels.DocumentModel() { Title = title }); await dtv.DecompileAsync(MainWindow.Instance.CurrentLanguage, nodes, new DecompilationOptions()); } } diff --git a/ILSpy/Commands/ShowDebugSteps.cs b/ILSpy/Commands/ShowDebugSteps.cs index d7b12f155..e9824b488 100644 --- a/ILSpy/Commands/ShowDebugSteps.cs +++ b/ILSpy/Commands/ShowDebugSteps.cs @@ -1,6 +1,8 @@ #if DEBUG +using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.Properties; +using ICSharpCode.ILSpy.ViewModels; namespace ICSharpCode.ILSpy.Commands { @@ -9,7 +11,7 @@ namespace ICSharpCode.ILSpy.Commands { public override void Execute(object parameter) { - DebugSteps.Show(); + DockWorkspace.Instance.ToolPanes.Add(DebugStepsPaneModel.Instance); } } } diff --git a/ILSpy/DebugSteps.xaml.cs b/ILSpy/DebugSteps.xaml.cs index ba13f1d84..12cb5f807 100644 --- a/ILSpy/DebugSteps.xaml.cs +++ b/ILSpy/DebugSteps.xaml.cs @@ -4,6 +4,8 @@ using System.Windows.Controls; using System.Windows.Input; using ICSharpCode.Decompiler.IL; using ICSharpCode.Decompiler.IL.Transforms; +using ICSharpCode.ILSpy.Docking; +using ICSharpCode.ILSpy.ViewModels; namespace ICSharpCode.ILSpy { @@ -20,7 +22,7 @@ namespace ICSharpCode.ILSpy ILAstLanguage language; #endif - DebugSteps() + public DebugSteps() { InitializeComponent(); @@ -79,7 +81,7 @@ namespace ICSharpCode.ILSpy public static void Show() { - MainWindow.Instance.ShowInNewPane(Properties.Resources.DebugSteps, new DebugSteps(), PanePosition.Top); + DockWorkspace.Instance.ToolPanes.Add(DebugStepsPaneModel.Instance); } void IPane.Closed() diff --git a/ILSpy/Docking/ActiveDocumentConverter.cs b/ILSpy/Docking/ActiveDocumentConverter.cs new file mode 100644 index 000000000..326d72ae2 --- /dev/null +++ b/ILSpy/Docking/ActiveDocumentConverter.cs @@ -0,0 +1,25 @@ +using System; +using System.Windows.Data; +using ICSharpCode.ILSpy.ViewModels; + +namespace ICSharpCode.ILSpy.Docking +{ + public class ActiveDocumentConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + if (value is DocumentModel) + return value; + + return Binding.DoNothing; + } + + public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + if (value is DocumentModel) + return value; + + return Binding.DoNothing; + } + } +} diff --git a/ILSpy/Docking/DockLayoutSettings.cs b/ILSpy/Docking/DockLayoutSettings.cs index 737910f6f..69ca8c541 100644 --- a/ILSpy/Docking/DockLayoutSettings.cs +++ b/ILSpy/Docking/DockLayoutSettings.cs @@ -32,7 +32,7 @@ namespace ICSharpCode.ILSpy.Docking public void Deserialize(XmlLayoutSerializer serializer) { if (!Valid) - return; + rawSettings = ""; using (StringReader reader = new StringReader(rawSettings)) { serializer.Deserialize(reader); diff --git a/ILSpy/Docking/DockWorkspace.cs b/ILSpy/Docking/DockWorkspace.cs new file mode 100644 index 000000000..7d6a5a3f7 --- /dev/null +++ b/ILSpy/Docking/DockWorkspace.cs @@ -0,0 +1,47 @@ +using System.Collections.ObjectModel; +using System.ComponentModel; +using ICSharpCode.ILSpy.ViewModels; + +namespace ICSharpCode.ILSpy.Docking +{ + public class DockWorkspace : INotifyPropertyChanged + { + public event PropertyChangedEventHandler PropertyChanged; + + public static DockWorkspace Instance { get; } = new DockWorkspace(); + + private DockWorkspace() + { + Documents.Add(new DocumentModel()); + ToolPanes.Add(AssemblyListPaneModel.Instance); + } + + public PaneCollection Documents { get; } = new PaneCollection(); + + public PaneCollection ToolPanes { get; } = new PaneCollection(); + + public void Remove(PaneModel model) + { + Documents.Remove(model as DocumentModel); + ToolPanes.Remove(model as ToolPaneModel); + } + + private DocumentModel _activeDocument = null; + public DocumentModel ActiveDocument { + get { + return _activeDocument; + } + set { + if (_activeDocument != value) { + _activeDocument = value; + RaisePropertyChanged(nameof(ActiveDocument)); + } + } + } + + protected void RaisePropertyChanged(string propertyName) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } +} diff --git a/ILSpy/Docking/DockingHelper.cs b/ILSpy/Docking/DockingHelper.cs index 157837a6c..7198d9b13 100644 --- a/ILSpy/Docking/DockingHelper.cs +++ b/ILSpy/Docking/DockingHelper.cs @@ -1,4 +1,5 @@ -using System.Windows; +using System.Linq; +using System.Windows; using System.Windows.Controls; using Xceed.Wpf.AvalonDock.Layout; @@ -6,7 +7,18 @@ namespace ICSharpCode.ILSpy.Docking { public static class DockingHelper { - public static void DockHorizontal(LayoutContent layoutContent, ILayoutElement paneRelativeTo, GridLength dockHeight, bool dockBefore = false) + public static bool Dock(LayoutRoot root, LayoutContent layoutContent, PanePosition position) + { + var documentPane = root.Descendents().OfType().FirstOrDefault(); + if ((position == PanePosition.Top) || (position == PanePosition.Bottom)) { + return DockHorizontal(layoutContent, documentPane, new GridLength(200), position == PanePosition.Top); + } else if ((position == PanePosition.Left) || (position == PanePosition.Right)) { + return DockVertical(layoutContent as LayoutAnchorable, documentPane, new GridLength(400), position == PanePosition.Left); + } + return false; + } + + public static bool DockHorizontal(LayoutContent layoutContent, ILayoutElement paneRelativeTo, GridLength dockHeight, bool dockBefore = false) { if (paneRelativeTo is ILayoutDocumentPane parentDocumentPane) { var parentDocumentGroup = paneRelativeTo.FindParent(); @@ -22,11 +34,39 @@ namespace ICSharpCode.ILSpy.Docking parentDocumentGroup.InsertChildAt(dockBefore ? indexOfParentPane : indexOfParentPane + 1, layoutDocumentPane); layoutContent.IsActive = true; layoutContent.Root.CollectGarbage(); - Application.Current.MainWindow.Dispatcher.Invoke(() => { + Application.Current.MainWindow.Dispatcher.Invoke( + () => layoutDocumentPane.DockHeight = dockHeight, + System.Windows.Threading.DispatcherPriority.Loaded); + return true; + } + + return false; + } + + public static bool DockVertical(LayoutAnchorable anchorable, ILayoutElement paneRelativeTo, GridLength dockWidth, bool dockBefore = false) + { + if (paneRelativeTo is ILayoutDocumentPane parentDocumentPane) { + var grandParent = parentDocumentPane.Parent as LayoutPanel; + var targetAnchorablePane = grandParent.Children.OfType().FirstOrDefault(); + if (targetAnchorablePane == null) { + targetAnchorablePane = new LayoutAnchorablePane() { + DockWidth = new GridLength(400) + }; + int targetIndex = dockBefore ? 0 : grandParent.ChildrenCount; + grandParent.InsertChildAt(targetIndex, targetAnchorablePane); + } + grandParent.Orientation = Orientation.Horizontal; + targetAnchorablePane.Children.Add(anchorable); - layoutDocumentPane.DockHeight = dockHeight; - }, System.Windows.Threading.DispatcherPriority.Loaded); + anchorable.IsActive = true; + anchorable.Root.CollectGarbage(); + Application.Current.MainWindow.Dispatcher.Invoke( + () => targetAnchorablePane.DockWidth = dockWidth, + System.Windows.Threading.DispatcherPriority.Loaded); + return true; } + + return false; } } } diff --git a/ILSpy/Docking/LayoutUpdateStrategy.cs b/ILSpy/Docking/LayoutUpdateStrategy.cs new file mode 100644 index 000000000..c63e2604c --- /dev/null +++ b/ILSpy/Docking/LayoutUpdateStrategy.cs @@ -0,0 +1,42 @@ +using System.Linq; +using System.Windows; +using ICSharpCode.ILSpy.ViewModels; +using Xceed.Wpf.AvalonDock.Layout; + +namespace ICSharpCode.ILSpy.Docking +{ + public class LayoutUpdateStrategy : ILayoutUpdateStrategy + { + public bool BeforeInsertAnchorable(LayoutRoot layout, LayoutAnchorable anchorableToShow, ILayoutContainer destinationContainer) + { + if ((destinationContainer != null) && + (destinationContainer.FindParent() != null)) + return false; + + PanePosition targetPosition = PanePosition.Top; + switch (anchorableToShow.Content) { + case AnalyzerPaneModel _: + targetPosition = PanePosition.Bottom; + break; + case AssemblyListPaneModel _: + targetPosition = PanePosition.Left; + break; + } + + return DockingHelper.Dock(layout, anchorableToShow, targetPosition); + } + + public void AfterInsertAnchorable(LayoutRoot layout, LayoutAnchorable anchorableShown) + { + } + + public bool BeforeInsertDocument(LayoutRoot layout, LayoutDocument anchorableToShow, ILayoutContainer destinationContainer) + { + return false; + } + + public void AfterInsertDocument(LayoutRoot layout, LayoutDocument anchorableShown) + { + } + } +} diff --git a/ILSpy/Docking/PaneCollection.cs b/ILSpy/Docking/PaneCollection.cs new file mode 100644 index 000000000..dfb9fd744 --- /dev/null +++ b/ILSpy/Docking/PaneCollection.cs @@ -0,0 +1,43 @@ +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Linq; +using ICSharpCode.ILSpy.ViewModels; + +namespace ICSharpCode.ILSpy.Docking +{ + public class PaneCollection : INotifyCollectionChanged, INotifyPropertyChanged, ICollection + where T : PaneModel + { + private ObservableCollection observableCollection = new ObservableCollection(); + + public event NotifyCollectionChangedEventHandler CollectionChanged; + public event PropertyChangedEventHandler PropertyChanged; + + public PaneCollection() + { + observableCollection.CollectionChanged += (sender, e) => CollectionChanged?.Invoke(this, e); + } + + public void Add(T item) + { + if (!this.Any(pane => pane.ContentId == item.ContentId)) { + observableCollection.Add(item); + } + + item.IsVisible = true; + item.IsActive = true; + } + + public int Count => observableCollection.Count(); + public bool IsReadOnly => false; + public void Clear() => observableCollection.Clear(); + public bool Contains(T item) => observableCollection.Contains(item); + public void CopyTo(T[] array, int arrayIndex) => observableCollection.CopyTo(array, arrayIndex); + public bool Remove(T item) => observableCollection.Remove(item); + public IEnumerator GetEnumerator() => observableCollection.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => observableCollection.GetEnumerator(); + } +} diff --git a/ILSpy/Docking/PanePosition.cs b/ILSpy/Docking/PanePosition.cs index d162d5d7b..719bcb44c 100644 --- a/ILSpy/Docking/PanePosition.cs +++ b/ILSpy/Docking/PanePosition.cs @@ -4,6 +4,8 @@ { Top, Bottom, + Left, + Right, Document } } diff --git a/ILSpy/Docking/PaneStyleSelector.cs b/ILSpy/Docking/PaneStyleSelector.cs new file mode 100644 index 000000000..c805066e6 --- /dev/null +++ b/ILSpy/Docking/PaneStyleSelector.cs @@ -0,0 +1,24 @@ +using System.Windows; +using System.Windows.Controls; +using ICSharpCode.ILSpy.ViewModels; + +namespace ICSharpCode.ILSpy.Docking +{ + public class PaneStyleSelector : StyleSelector + { + public Style ToolPaneStyle { get; set; } + + public Style DocumentStyle { get; set; } + + public override Style SelectStyle(object item, DependencyObject container) + { + if (item is DocumentModel) + return DocumentStyle; + + if (item is ToolPaneModel) + return ToolPaneStyle; + + return base.SelectStyle(item, container); + } + } +} diff --git a/ILSpy/Docking/PaneTemplateSelector.cs b/ILSpy/Docking/PaneTemplateSelector.cs new file mode 100644 index 000000000..ad94e8d8d --- /dev/null +++ b/ILSpy/Docking/PaneTemplateSelector.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.ObjectModel; +using System.Linq; +using System.Windows; +using System.Windows.Controls; + +namespace ICSharpCode.ILSpy.Docking +{ + public class TemplateMapping + { + public Type Type { get; set; } + public DataTemplate Template { get; set; } + } + + public class PaneTemplateSelector : DataTemplateSelector + { + public Collection Mappings { get; set; } = new Collection(); + + public override DataTemplate SelectTemplate(object item, DependencyObject container) + { + return Mappings.FirstOrDefault(m => m.Type == item.GetType())?.Template + ?? base.SelectTemplate(item, container); + } + } +} diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index 2caf98878..8453880bd 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -138,8 +138,20 @@ DebugSteps.xaml + + + + + + + + + + + + @@ -252,6 +264,7 @@ + LGPL.txt diff --git a/ILSpy/MainWindow.xaml b/ILSpy/MainWindow.xaml index e34781457..a07bc2b93 100644 --- a/ILSpy/MainWindow.xaml +++ b/ILSpy/MainWindow.xaml @@ -5,8 +5,11 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:tv="clr-namespace:ICSharpCode.TreeView;assembly=ICSharpCode.TreeView" xmlns:local="clr-namespace:ICSharpCode.ILSpy" xmlns:avalondock="http://schemas.xceed.com/wpf/xaml/avalondock" + xmlns:docking="clr-namespace:ICSharpCode.ILSpy.Docking" xmlns:controls="clr-namespace:ICSharpCode.ILSpy.Controls" - xmlns:properties="clr-namespace:ICSharpCode.ILSpy.Properties" + xmlns:analyzers="clr-namespace:ICSharpCode.ILSpy.Analyzers" + xmlns:properties="clr-namespace:ICSharpCode.ILSpy.Properties" + xmlns:viewmodels="clr-namespace:ICSharpCode.ILSpy.ViewModels" Title="ILSpy" MinWidth="250" MinHeight="200" @@ -18,7 +21,46 @@ > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + @@ -79,23 +121,23 @@ - + - + - + + SelectedItem="{Binding SessionSettings.FilterSettings.Language}"/> + SelectedItem="{Binding SessionSettings.FilterSettings.LanguageVersion, UpdateSourceTrigger=PropertyChanged}"/> @@ -116,41 +158,61 @@ Text="{x:Static properties:Resources.StandBy}"/> - - - - - - - - - - - - - + DataContext="{Binding Workspace}" + AnchorablesSource="{Binding ToolPanes}" + DocumentsSource="{Binding Documents}" + ActiveContent="{Binding ActiveDocument, Mode=Default, Converter={StaticResource ActiveDocumentConverter}}" + AllowMixedOrientation="True"> - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs index 7bff4aaae..1a597a847 100644 --- a/ILSpy/MainWindow.xaml.cs +++ b/ILSpy/MainWindow.xaml.cs @@ -38,9 +38,12 @@ using ICSharpCode.Decompiler.Documentation; using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem.Implementation; +using ICSharpCode.ILSpy.Analyzers; using ICSharpCode.ILSpy.Controls; +using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TreeNodes; +using ICSharpCode.ILSpy.ViewModels; using ICSharpCode.TreeView; using Microsoft.Win32; using OSVersionHelper; @@ -49,6 +52,12 @@ using Xceed.Wpf.AvalonDock.Layout.Serialization; namespace ICSharpCode.ILSpy { + class MainWindowDataContext + { + public DockWorkspace Workspace { get; set; } + public SessionSettings SessionSettings { get; set; } + } + /// /// The main window of the application. /// @@ -76,6 +85,30 @@ namespace ICSharpCode.ILSpy get { return sessionSettings; } } + public ContentPresenter mainPane { + get { + return FindResource("MainPane") as ContentPresenter; + } + } + + public SharpTreeView treeView { + get { + return FindResource("TreeView") as SharpTreeView; + } + } + + public AnalyzerTreeView AnalyzerTreeView { + get { + return FindResource("AnalyzerTreeView") as AnalyzerTreeView; + } + } + + public SearchPane SearchPane { + get { + return FindResource("SearchPane") as SearchPane; + } + } + public MainWindow() { instance = this; @@ -86,9 +119,13 @@ namespace ICSharpCode.ILSpy this.Icon = new BitmapImage(new Uri("pack://application:,,,/ILSpy;component/images/ILSpy.ico")); - this.DataContext = sessionSettings; + this.DataContext = new MainWindowDataContext { + Workspace = DockWorkspace.Instance, + SessionSettings = sessionSettings + }; InitializeComponent(); + decompilerTextView = App.ExportProvider.GetExportedValue(); mainPane.Content = decompilerTextView; @@ -295,8 +332,8 @@ namespace ICSharpCode.ILSpy commandLineLoadedAssemblies.Clear(); // clear references once we don't need them anymore NavigateOnLaunch(args.NavigateTo, sessionSettings.ActiveTreeViewPath, spySettings, relevantAssemblies); if (args.Search != null) { - SearchPane.Instance.SearchTerm = args.Search; - SearchPane.Instance.Show(); + SearchPane.SearchTerm = args.Search; + SearchPane.Show(); } } @@ -877,7 +914,7 @@ namespace ICSharpCode.ILSpy void SearchCommandExecuted(object sender, ExecutedRoutedEventArgs e) { - SearchPane.Instance.Show(); + DockWorkspace.Instance.ToolPanes.Add(SearchPaneModel.Instance); } #endregion @@ -1037,22 +1074,22 @@ namespace ICSharpCode.ILSpy return loadedAssy.FileName; } - #region Top/Bottom Pane management + //#region Top/Bottom Pane management - public void ShowInNewPane(string title, object content, PanePosition panePosition, string toolTip = null) - { - if (panePosition == PanePosition.Document) { - var layoutDocument = new LayoutDocument() { Title = title, Content = content, ToolTip = toolTip, CanClose = true }; - var documentPane = this.DockManager.Layout.Descendents().OfType().FirstOrDefault(); - documentPane.Children.Add(layoutDocument); - } else { - var layoutAnchorable = new LayoutAnchorable() { Title = title, Content = content, ToolTip = toolTip, CanClose = true, CanHide = true }; - var documentPane = this.DockManager.Layout.Descendents().OfType().FirstOrDefault(); - Docking.DockingHelper.DockHorizontal(layoutAnchorable, documentPane, new GridLength(200), panePosition == PanePosition.Top); - } - } + //public void ShowInNewPane(string title, object content, PanePosition panePosition, string toolTip = null) + //{ + // if (panePosition == PanePosition.Document) { + // var layoutDocument = new LayoutDocument() { Title = title, Content = content, ToolTip = toolTip, CanClose = true }; + // var documentPane = this.DockManager.Layout.Descendents().OfType().FirstOrDefault(); + // documentPane.Children.Add(layoutDocument); + // } else { + // var layoutAnchorable = new LayoutAnchorable() { Title = title, Content = content, ToolTip = toolTip, CanClose = true, CanHide = true }; + // var documentPane = this.DockManager.Layout.Descendents().OfType().FirstOrDefault(); + // Docking.DockingHelper.DockHorizontal(layoutAnchorable, documentPane, new GridLength(200), panePosition == PanePosition.Top); + // } + //} - #endregion + //#endregion public void UnselectAll() { @@ -1076,5 +1113,10 @@ namespace ICSharpCode.ILSpy { return toolBar.Items; } + + private void DockManager_DocumentClosed(object sender, Xceed.Wpf.AvalonDock.DocumentClosedEventArgs e) + { + + } } } diff --git a/ILSpy/Search/SearchPane.cs b/ILSpy/Search/SearchPane.cs index 2201273eb..91fad1788 100644 --- a/ILSpy/Search/SearchPane.cs +++ b/ILSpy/Search/SearchPane.cs @@ -31,7 +31,9 @@ using System.Windows.Input; using System.Windows.Media; using System.Windows.Threading; using ICSharpCode.Decompiler.TypeSystem; +using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.Search; +using ICSharpCode.ILSpy.ViewModels; namespace ICSharpCode.ILSpy { @@ -42,7 +44,6 @@ namespace ICSharpCode.ILSpy { const int MAX_RESULTS = 1000; const int MAX_REFRESH_TIME_MS = 10; // More means quicker forward of data, less means better responsibility - static SearchPane instance; RunningSearch currentSearch; bool runSearchOnNextShow; @@ -53,17 +54,7 @@ namespace ICSharpCode.ILSpy get { return (ObservableCollection)GetValue(ResultsProperty); } } - public static SearchPane Instance { - get { - if (instance == null) { - App.Current.VerifyAccess(); - instance = new SearchPane(); - } - return instance; - } - } - - private SearchPane() + public SearchPane() { InitializeComponent(); searchModeComboBox.Items.Add(new { Image = Images.Library, Name = "Types and Members" }); @@ -114,7 +105,7 @@ namespace ICSharpCode.ILSpy public void Show() { if (!IsVisible) { - MainWindow.Instance.ShowInNewPane(Properties.Resources.SearchPane_Search, this, PanePosition.Top); + DockWorkspace.Instance.ToolPanes.Add(SearchPaneModel.Instance); if (runSearchOnNextShow) { runSearchOnNextShow = false; StartSearch(this.SearchTerm); diff --git a/ILSpy/ViewModels/AnalyzerPaneModel.cs b/ILSpy/ViewModels/AnalyzerPaneModel.cs new file mode 100644 index 000000000..aab12aa13 --- /dev/null +++ b/ILSpy/ViewModels/AnalyzerPaneModel.cs @@ -0,0 +1,15 @@ +namespace ICSharpCode.ILSpy.ViewModels +{ + public class AnalyzerPaneModel : ToolPaneModel + { + public const string PaneContentId = "analyzerPane"; + + public static AnalyzerPaneModel Instance { get; } = new AnalyzerPaneModel(); + + private AnalyzerPaneModel() + { + ContentId = PaneContentId; + Title = Properties.Resources.Analyze; + } + } +} diff --git a/ILSpy/ViewModels/AssemblyListPaneModel.cs b/ILSpy/ViewModels/AssemblyListPaneModel.cs new file mode 100644 index 000000000..8ec178596 --- /dev/null +++ b/ILSpy/ViewModels/AssemblyListPaneModel.cs @@ -0,0 +1,16 @@ +namespace ICSharpCode.ILSpy.ViewModels +{ + public class AssemblyListPaneModel : ToolPaneModel + { + public const string PaneContentId = "assemblyListPane"; + + public static AssemblyListPaneModel Instance { get; } = new AssemblyListPaneModel(); + + private AssemblyListPaneModel() + { + Title = "Assemblies"; + ContentId = PaneContentId; + IsCloseable = false; + } + } +} diff --git a/ILSpy/ViewModels/DebugStepsPaneModel.cs b/ILSpy/ViewModels/DebugStepsPaneModel.cs new file mode 100644 index 000000000..503ddf8d5 --- /dev/null +++ b/ILSpy/ViewModels/DebugStepsPaneModel.cs @@ -0,0 +1,15 @@ +namespace ICSharpCode.ILSpy.ViewModels +{ + public class DebugStepsPaneModel : ToolPaneModel + { + public const string PaneContentId = "debugStepsPane"; + + public static DebugStepsPaneModel Instance { get; } = new DebugStepsPaneModel(); + + private DebugStepsPaneModel() + { + ContentId = PaneContentId; + Title = Properties.Resources.DebugSteps; + } + } +} diff --git a/ILSpy/ViewModels/DocumentModel.cs b/ILSpy/ViewModels/DocumentModel.cs new file mode 100644 index 000000000..0200735e1 --- /dev/null +++ b/ILSpy/ViewModels/DocumentModel.cs @@ -0,0 +1,12 @@ +namespace ICSharpCode.ILSpy.ViewModels +{ + public class DocumentModel : PaneModel + { + public DocumentModel() + { + ContentId = "document"; + Title = "View"; + IsCloseable = false; + } + } +} diff --git a/ILSpy/ViewModels/PaneModel.cs b/ILSpy/ViewModels/PaneModel.cs new file mode 100644 index 000000000..2a168f9ae --- /dev/null +++ b/ILSpy/ViewModels/PaneModel.cs @@ -0,0 +1,80 @@ +using System.ComponentModel; + +namespace ICSharpCode.ILSpy.ViewModels +{ + public class PaneModel : INotifyPropertyChanged + { + public event PropertyChangedEventHandler PropertyChanged; + + protected void RaisePropertyChanged(string propertyName) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + private bool isSelected = false; + public bool IsSelected { + get => isSelected; + set { + if (isSelected != value) { + isSelected = value; + RaisePropertyChanged(nameof(IsSelected)); + } + } + } + + private bool isActive = false; + public bool IsActive { + get => isActive; + set { + if (isActive != value) { + isActive = value; + RaisePropertyChanged(nameof(IsActive)); + } + } + } + + private bool isVisible = true; + public bool IsVisible { + get { return isVisible; } + set { + if (isVisible != value) { + isVisible = value; + RaisePropertyChanged(nameof(IsVisible)); + } + } + } + + private bool isCloseable = true; + public bool IsCloseable { + get { return isCloseable; } + set { + if (isCloseable != value) { + isCloseable = value; + RaisePropertyChanged(nameof(IsCloseable)); + } + } + } + + private string contentId; + public string ContentId { + get => contentId; + set { + if (contentId != value) { + contentId = value; + RaisePropertyChanged(nameof(ContentId)); + } + } + } + + private string title; + public string Title { + get => title; + set { + if (title != value) { + title = value; + RaisePropertyChanged(nameof(Title)); + } + } + } + } +} diff --git a/ILSpy/ViewModels/SearchPaneModel.cs b/ILSpy/ViewModels/SearchPaneModel.cs new file mode 100644 index 000000000..585e1b5be --- /dev/null +++ b/ILSpy/ViewModels/SearchPaneModel.cs @@ -0,0 +1,16 @@ +namespace ICSharpCode.ILSpy.ViewModels +{ + public class SearchPaneModel : ToolPaneModel + { + public const string PaneContentId = "searchPane"; + + public static SearchPaneModel Instance { get; } = new SearchPaneModel(); + + private SearchPaneModel() + { + ContentId = PaneContentId; + Title = Properties.Resources.SearchPane_Search; + IsCloseable = true; + } + } +} diff --git a/ILSpy/ViewModels/ToolPaneModel.cs b/ILSpy/ViewModels/ToolPaneModel.cs new file mode 100644 index 000000000..fdb45bf76 --- /dev/null +++ b/ILSpy/ViewModels/ToolPaneModel.cs @@ -0,0 +1,7 @@ +namespace ICSharpCode.ILSpy.ViewModels +{ + public class ToolPaneModel : PaneModel + { + + } +} From 69a7ffd61a163ed835576f28ce8a6aa3fdc553ce Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 2 Nov 2019 16:18:16 +0100 Subject: [PATCH 02/12] Improved docking. --- ILSpy/Docking/DockWorkspace.cs | 2 - ILSpy/Docking/DockingHelper.cs | 72 ----- ILSpy/Docking/LayoutUpdateStrategy.cs | 109 +++++++- ILSpy/ILSpy.csproj | 3 +- ILSpy/MainWindow.xaml | 320 +++++++++++++++++++++- ILSpy/MainWindow.xaml.cs | 20 +- ILSpy/ViewModels/AnalyzerPaneModel.cs | 2 + ILSpy/ViewModels/AssemblyListPaneModel.cs | 2 + ILSpy/ViewModels/DebugStepsPaneModel.cs | 2 + ILSpy/ViewModels/DocumentModel.cs | 2 + ILSpy/ViewModels/PaneModel.cs | 5 +- ILSpy/ViewModels/SearchPaneModel.cs | 2 + ILSpy/ViewModels/ToolPaneModel.cs | 2 +- 13 files changed, 424 insertions(+), 119 deletions(-) delete mode 100644 ILSpy/Docking/DockingHelper.cs diff --git a/ILSpy/Docking/DockWorkspace.cs b/ILSpy/Docking/DockWorkspace.cs index 7d6a5a3f7..71999a01b 100644 --- a/ILSpy/Docking/DockWorkspace.cs +++ b/ILSpy/Docking/DockWorkspace.cs @@ -12,8 +12,6 @@ namespace ICSharpCode.ILSpy.Docking private DockWorkspace() { - Documents.Add(new DocumentModel()); - ToolPanes.Add(AssemblyListPaneModel.Instance); } public PaneCollection Documents { get; } = new PaneCollection(); diff --git a/ILSpy/Docking/DockingHelper.cs b/ILSpy/Docking/DockingHelper.cs deleted file mode 100644 index 7198d9b13..000000000 --- a/ILSpy/Docking/DockingHelper.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System.Linq; -using System.Windows; -using System.Windows.Controls; -using Xceed.Wpf.AvalonDock.Layout; - -namespace ICSharpCode.ILSpy.Docking -{ - public static class DockingHelper - { - public static bool Dock(LayoutRoot root, LayoutContent layoutContent, PanePosition position) - { - var documentPane = root.Descendents().OfType().FirstOrDefault(); - if ((position == PanePosition.Top) || (position == PanePosition.Bottom)) { - return DockHorizontal(layoutContent, documentPane, new GridLength(200), position == PanePosition.Top); - } else if ((position == PanePosition.Left) || (position == PanePosition.Right)) { - return DockVertical(layoutContent as LayoutAnchorable, documentPane, new GridLength(400), position == PanePosition.Left); - } - return false; - } - - public static bool DockHorizontal(LayoutContent layoutContent, ILayoutElement paneRelativeTo, GridLength dockHeight, bool dockBefore = false) - { - if (paneRelativeTo is ILayoutDocumentPane parentDocumentPane) { - var parentDocumentGroup = paneRelativeTo.FindParent(); - if (parentDocumentGroup == null) { - var grandParent = parentDocumentPane.Parent as ILayoutContainer; - parentDocumentGroup = new LayoutDocumentPaneGroup() { Orientation = System.Windows.Controls.Orientation.Vertical }; - grandParent.ReplaceChild(paneRelativeTo, parentDocumentGroup); - parentDocumentGroup.Children.Add(parentDocumentPane); - } - parentDocumentGroup.Orientation = System.Windows.Controls.Orientation.Vertical; - int indexOfParentPane = parentDocumentGroup.IndexOfChild(parentDocumentPane); - var layoutDocumentPane = new LayoutDocumentPane(layoutContent) { DockHeight = dockHeight }; - parentDocumentGroup.InsertChildAt(dockBefore ? indexOfParentPane : indexOfParentPane + 1, layoutDocumentPane); - layoutContent.IsActive = true; - layoutContent.Root.CollectGarbage(); - Application.Current.MainWindow.Dispatcher.Invoke( - () => layoutDocumentPane.DockHeight = dockHeight, - System.Windows.Threading.DispatcherPriority.Loaded); - return true; - } - - return false; - } - - public static bool DockVertical(LayoutAnchorable anchorable, ILayoutElement paneRelativeTo, GridLength dockWidth, bool dockBefore = false) - { - if (paneRelativeTo is ILayoutDocumentPane parentDocumentPane) { - var grandParent = parentDocumentPane.Parent as LayoutPanel; - var targetAnchorablePane = grandParent.Children.OfType().FirstOrDefault(); - if (targetAnchorablePane == null) { - targetAnchorablePane = new LayoutAnchorablePane() { - DockWidth = new GridLength(400) - }; - int targetIndex = dockBefore ? 0 : grandParent.ChildrenCount; - grandParent.InsertChildAt(targetIndex, targetAnchorablePane); - } - grandParent.Orientation = Orientation.Horizontal; - targetAnchorablePane.Children.Add(anchorable); - - anchorable.IsActive = true; - anchorable.Root.CollectGarbage(); - Application.Current.MainWindow.Dispatcher.Invoke( - () => targetAnchorablePane.DockWidth = dockWidth, - System.Windows.Threading.DispatcherPriority.Loaded); - return true; - } - - return false; - } - } -} diff --git a/ILSpy/Docking/LayoutUpdateStrategy.cs b/ILSpy/Docking/LayoutUpdateStrategy.cs index c63e2604c..751e6abde 100644 --- a/ILSpy/Docking/LayoutUpdateStrategy.cs +++ b/ILSpy/Docking/LayoutUpdateStrategy.cs @@ -1,5 +1,7 @@ -using System.Linq; +using System; +using System.Linq; using System.Windows; +using System.Windows.Controls; using ICSharpCode.ILSpy.ViewModels; using Xceed.Wpf.AvalonDock.Layout; @@ -9,21 +11,71 @@ namespace ICSharpCode.ILSpy.Docking { public bool BeforeInsertAnchorable(LayoutRoot layout, LayoutAnchorable anchorableToShow, ILayoutContainer destinationContainer) { - if ((destinationContainer != null) && - (destinationContainer.FindParent() != null)) + if (destinationContainer?.FindParent() != null) return false; - PanePosition targetPosition = PanePosition.Top; - switch (anchorableToShow.Content) { - case AnalyzerPaneModel _: - targetPosition = PanePosition.Bottom; - break; - case AssemblyListPaneModel _: - targetPosition = PanePosition.Left; - break; + PanePosition targetPosition = anchorableToShow.Content is PaneModel model ? model.DefaultPosition : PanePosition.Document; + + switch (targetPosition) { + case PanePosition.Top: + case PanePosition.Bottom: + case PanePosition.Left: + case PanePosition.Right: + var pane = GetOrCreatePane(layout, targetPosition.ToString()); + if (pane == null) + return false; + anchorableToShow.CanDockAsTabbedDocument = false; + pane.Children.Add(anchorableToShow); + return true; + case PanePosition.Document: + var documentPane = GetOrCreateDocumentPane(layout); + if (documentPane == null) + return false; + documentPane.Children.Add(anchorableToShow); + return true; + default: + throw new NotSupportedException($"Enum value {targetPosition} is not supported"); } + } - return DockingHelper.Dock(layout, anchorableToShow, targetPosition); + private LayoutAnchorablePane GetOrCreatePane(LayoutRoot layout, string name) + { + var pane = layout.Descendents().OfType().FirstOrDefault(p => p.Name == name + "Pane"); + if (pane != null) + return pane; + var layoutPanel = layout.Children.OfType().FirstOrDefault(); + if (layoutPanel == null) { + layout.RootPanel = new LayoutPanel() { Orientation = Orientation.Horizontal }; + } + if (layoutPanel.Orientation != Orientation.Horizontal) { + layoutPanel.Orientation = Orientation.Horizontal; + } + LayoutAnchorablePane result = null; + switch (name) { + case "Top": + case "Bottom": + var centerLayoutPanel = layoutPanel.Children.OfType().FirstOrDefault(); + if (centerLayoutPanel == null) { + layoutPanel.Children.Insert(0, centerLayoutPanel = new LayoutPanel() { Orientation = Orientation.Vertical }); + } + if (centerLayoutPanel.Orientation != Orientation.Vertical) { + centerLayoutPanel.Orientation = Orientation.Vertical; + } + if (name == "Top") + centerLayoutPanel.Children.Insert(0, result = new LayoutAnchorablePane { Name = name + "Pane", DockMinHeight = 250 }); + else + centerLayoutPanel.Children.Add(result = new LayoutAnchorablePane { Name = name + "Pane", DockMinHeight = 250 }); + return result; + case "Left": + case "Right": + if (name == "Left") + layoutPanel.Children.Insert(0, result = new LayoutAnchorablePane { Name = name + "Pane", DockMinWidth = 250 }); + else + layoutPanel.Children.Add(result = new LayoutAnchorablePane { Name = name + "Pane", DockMinWidth = 250 }); + return result; + default: + throw new NotImplementedException(); + } } public void AfterInsertAnchorable(LayoutRoot layout, LayoutAnchorable anchorableShown) @@ -32,7 +84,38 @@ namespace ICSharpCode.ILSpy.Docking public bool BeforeInsertDocument(LayoutRoot layout, LayoutDocument anchorableToShow, ILayoutContainer destinationContainer) { - return false; + if (destinationContainer?.FindParent() != null) + return false; + + var documentPane = GetOrCreateDocumentPane(layout); + if (documentPane == null) + return false; + documentPane.Children.Add(anchorableToShow); + return true; + } + + private LayoutDocumentPane GetOrCreateDocumentPane(LayoutRoot layout) + { + var pane = layout.Descendents().OfType().FirstOrDefault(); + if (pane != null) + return pane; + var layoutPanel = layout.Children.OfType().FirstOrDefault(); + if (layoutPanel == null) { + layout.RootPanel = new LayoutPanel() { Orientation = Orientation.Horizontal }; + } + if (layoutPanel.Orientation != Orientation.Horizontal) { + layoutPanel.Orientation = Orientation.Horizontal; + } + var centerLayoutPanel = layoutPanel.Children.OfType().FirstOrDefault(); + if (centerLayoutPanel == null) { + layoutPanel.Children.Insert(0, centerLayoutPanel = new LayoutPanel() { Orientation = Orientation.Vertical }); + } + if (centerLayoutPanel.Orientation != Orientation.Vertical) { + centerLayoutPanel.Orientation = Orientation.Vertical; + } + LayoutDocumentPane result; + centerLayoutPanel.Children.Add(result = new LayoutDocumentPane()); + return result; } public void AfterInsertDocument(LayoutRoot layout, LayoutDocument anchorableShown) diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index c53b9deef..a6fc565f2 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -50,7 +50,7 @@ - + @@ -141,7 +141,6 @@ - diff --git a/ILSpy/MainWindow.xaml b/ILSpy/MainWindow.xaml index a07bc2b93..eaf340173 100644 --- a/ILSpy/MainWindow.xaml +++ b/ILSpy/MainWindow.xaml @@ -5,6 +5,7 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:tv="clr-namespace:ICSharpCode.TreeView;assembly=ICSharpCode.TreeView" xmlns:local="clr-namespace:ICSharpCode.ILSpy" xmlns:avalondock="http://schemas.xceed.com/wpf/xaml/avalondock" + xmlns:avalondockproperties="clr-namespace:Xceed.Wpf.AvalonDock.Properties;assembly=Xceed.Wpf.AvalonDock" xmlns:docking="clr-namespace:ICSharpCode.ILSpy.Docking" xmlns:controls="clr-namespace:ICSharpCode.ILSpy.Controls" xmlns:analyzers="clr-namespace:ICSharpCode.ILSpy.Analyzers" @@ -22,7 +23,8 @@ - + + - + @@ -42,11 +44,11 @@ - + - + @@ -162,16 +164,313 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -191,14 +490,13 @@ - @@ -208,7 +506,7 @@ - + diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs index 1916794ae..bff8bd646 100644 --- a/ILSpy/MainWindow.xaml.cs +++ b/ILSpy/MainWindow.xaml.cs @@ -460,6 +460,9 @@ namespace ICSharpCode.ILSpy void MainWindow_Loaded(object sender, RoutedEventArgs e) { + DockWorkspace.Instance.ToolPanes.Add(AssemblyListPaneModel.Instance); + DockWorkspace.Instance.Documents.Add(new DocumentModel()); + ILSpySettings spySettings = this.spySettingsForMainWindow_Loaded; this.spySettingsForMainWindow_Loaded = null; var loadPreviousAssemblies = Options.MiscSettingsPanel.CurrentMiscSettings.LoadPreviousAssemblies; @@ -1074,23 +1077,6 @@ namespace ICSharpCode.ILSpy return loadedAssy.FileName; } - //#region Top/Bottom Pane management - - //public void ShowInNewPane(string title, object content, PanePosition panePosition, string toolTip = null) - //{ - // if (panePosition == PanePosition.Document) { - // var layoutDocument = new LayoutDocument() { Title = title, Content = content, ToolTip = toolTip, CanClose = true }; - // var documentPane = this.DockManager.Layout.Descendents().OfType().FirstOrDefault(); - // documentPane.Children.Add(layoutDocument); - // } else { - // var layoutAnchorable = new LayoutAnchorable() { Title = title, Content = content, ToolTip = toolTip, CanClose = true, CanHide = true }; - // var documentPane = this.DockManager.Layout.Descendents().OfType().FirstOrDefault(); - // Docking.DockingHelper.DockHorizontal(layoutAnchorable, documentPane, new GridLength(200), panePosition == PanePosition.Top); - // } - //} - - //#endregion - public void UnselectAll() { treeView.UnselectAll(); diff --git a/ILSpy/ViewModels/AnalyzerPaneModel.cs b/ILSpy/ViewModels/AnalyzerPaneModel.cs index aab12aa13..0eaf9c818 100644 --- a/ILSpy/ViewModels/AnalyzerPaneModel.cs +++ b/ILSpy/ViewModels/AnalyzerPaneModel.cs @@ -6,6 +6,8 @@ public static AnalyzerPaneModel Instance { get; } = new AnalyzerPaneModel(); + public override PanePosition DefaultPosition => PanePosition.Bottom; + private AnalyzerPaneModel() { ContentId = PaneContentId; diff --git a/ILSpy/ViewModels/AssemblyListPaneModel.cs b/ILSpy/ViewModels/AssemblyListPaneModel.cs index 8ec178596..2d465a6a8 100644 --- a/ILSpy/ViewModels/AssemblyListPaneModel.cs +++ b/ILSpy/ViewModels/AssemblyListPaneModel.cs @@ -6,6 +6,8 @@ public static AssemblyListPaneModel Instance { get; } = new AssemblyListPaneModel(); + public override PanePosition DefaultPosition => PanePosition.Left; + private AssemblyListPaneModel() { Title = "Assemblies"; diff --git a/ILSpy/ViewModels/DebugStepsPaneModel.cs b/ILSpy/ViewModels/DebugStepsPaneModel.cs index 503ddf8d5..196e9a7be 100644 --- a/ILSpy/ViewModels/DebugStepsPaneModel.cs +++ b/ILSpy/ViewModels/DebugStepsPaneModel.cs @@ -6,6 +6,8 @@ public static DebugStepsPaneModel Instance { get; } = new DebugStepsPaneModel(); + public override PanePosition DefaultPosition => PanePosition.Top; + private DebugStepsPaneModel() { ContentId = PaneContentId; diff --git a/ILSpy/ViewModels/DocumentModel.cs b/ILSpy/ViewModels/DocumentModel.cs index 0200735e1..2fa9129ab 100644 --- a/ILSpy/ViewModels/DocumentModel.cs +++ b/ILSpy/ViewModels/DocumentModel.cs @@ -2,6 +2,8 @@ { public class DocumentModel : PaneModel { + public override PanePosition DefaultPosition => PanePosition.Document; + public DocumentModel() { ContentId = "document"; diff --git a/ILSpy/ViewModels/PaneModel.cs b/ILSpy/ViewModels/PaneModel.cs index 2a168f9ae..bce2ecc70 100644 --- a/ILSpy/ViewModels/PaneModel.cs +++ b/ILSpy/ViewModels/PaneModel.cs @@ -1,9 +1,12 @@ using System.ComponentModel; +using System.Windows.Input; namespace ICSharpCode.ILSpy.ViewModels { - public class PaneModel : INotifyPropertyChanged + public abstract class PaneModel : INotifyPropertyChanged { + public abstract PanePosition DefaultPosition { get; } + public event PropertyChangedEventHandler PropertyChanged; protected void RaisePropertyChanged(string propertyName) diff --git a/ILSpy/ViewModels/SearchPaneModel.cs b/ILSpy/ViewModels/SearchPaneModel.cs index 585e1b5be..2b3847817 100644 --- a/ILSpy/ViewModels/SearchPaneModel.cs +++ b/ILSpy/ViewModels/SearchPaneModel.cs @@ -6,6 +6,8 @@ public static SearchPaneModel Instance { get; } = new SearchPaneModel(); + public override PanePosition DefaultPosition => PanePosition.Top; + private SearchPaneModel() { ContentId = PaneContentId; diff --git a/ILSpy/ViewModels/ToolPaneModel.cs b/ILSpy/ViewModels/ToolPaneModel.cs index fdb45bf76..e57a18067 100644 --- a/ILSpy/ViewModels/ToolPaneModel.cs +++ b/ILSpy/ViewModels/ToolPaneModel.cs @@ -1,6 +1,6 @@ namespace ICSharpCode.ILSpy.ViewModels { - public class ToolPaneModel : PaneModel + public abstract class ToolPaneModel : PaneModel { } From 6e3fc35d0331172838bea189be42fe879c816dde Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 16 Nov 2019 13:55:22 +0100 Subject: [PATCH 03/12] Add AvalonDock as submodule for the time being. --- .gitmodules | 5 ++++- AvalonDock | 1 + ILSpy.sln | 6 ++++++ ILSpy/ILSpy.csproj | 2 +- 4 files changed, 12 insertions(+), 2 deletions(-) create mode 160000 AvalonDock diff --git a/.gitmodules b/.gitmodules index 4566a77eb..ed9a2a9ab 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,7 @@ [submodule "ILSpy-tests"] path = ILSpy-tests url = https://github.com/icsharpcode/ILSpy-tests - \ No newline at end of file + +[submodule "AvalonDock"] + path = AvalonDock + url = https://github.com/siegfriedpammer/AvalonDock diff --git a/AvalonDock b/AvalonDock new file mode 160000 index 000000000..e5ec95d62 --- /dev/null +++ b/AvalonDock @@ -0,0 +1 @@ +Subproject commit e5ec95d624d5c3e6998832c4d8adefdaf11fd9c8 diff --git a/ILSpy.sln b/ILSpy.sln index 58bdc2b3e..fba43890f 100644 --- a/ILSpy.sln +++ b/ILSpy.sln @@ -33,6 +33,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ICSharpCode.Decompiler.PdbP EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILSpy.Tests", "ILSpy.Tests\ILSpy.Tests.csproj", "{B51C6636-B8D1-4200-9869-08F2689DE6C2}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xceed.Wpf.AvalonDock", "AvalonDock\source\Components\Xceed.Wpf.AvalonDock\Xceed.Wpf.AvalonDock.csproj", "{D87D783A-A8EE-4A36-AAED-3AB21DC98046}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -79,6 +81,10 @@ Global {B51C6636-B8D1-4200-9869-08F2689DE6C2}.Debug|Any CPU.Build.0 = Debug|Any CPU {B51C6636-B8D1-4200-9869-08F2689DE6C2}.Release|Any CPU.ActiveCfg = Release|Any CPU {B51C6636-B8D1-4200-9869-08F2689DE6C2}.Release|Any CPU.Build.0 = Release|Any CPU + {D87D783A-A8EE-4A36-AAED-3AB21DC98046}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D87D783A-A8EE-4A36-AAED-3AB21DC98046}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D87D783A-A8EE-4A36-AAED-3AB21DC98046}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D87D783A-A8EE-4A36-AAED-3AB21DC98046}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index a6fc565f2..54176b95d 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -50,7 +50,6 @@ - @@ -60,6 +59,7 @@ + From 84bb61cc5bd0f09f5a22890a7d2b108bd05a50de Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 16 Nov 2019 13:56:46 +0100 Subject: [PATCH 04/12] Add primitive multi-document support. --- ILSpy/AboutPage.cs | 5 +- ILSpy/App.xaml.cs | 2 +- ILSpy/Commands/DecompileAllCommand.cs | 8 +- ILSpy/Commands/DecompileInNewViewCommand.cs | 15 +- ILSpy/Commands/DisassembleAllCommand.cs | 4 +- ILSpy/Commands/GeneratePdbContextMenuEntry.cs | 4 +- ILSpy/Commands/Pdb2XmlCommand.cs | 4 +- ILSpy/Commands/SaveCodeContextMenuEntry.cs | 2 +- ILSpy/ContextMenuEntry.cs | 36 ++- ILSpy/DebugSteps.xaml.cs | 4 +- ILSpy/Docking/DockWorkspace.cs | 32 +- ILSpy/MainWindow.xaml | 306 +----------------- ILSpy/MainWindow.xaml.cs | 31 +- ILSpy/TaskHelper.cs | 2 +- ILSpy/TextView/DecompilerTextView.cs | 14 +- ILSpy/TextView/DecompilerTextView.xaml | 5 +- .../ResourceNodes/ResourceTreeNode.cs | 2 +- ILSpy/ViewModels/DocumentModel.cs | 38 ++- ILSpy/ViewModels/PaneModel.cs | 41 ++- 19 files changed, 185 insertions(+), 370 deletions(-) diff --git a/ILSpy/AboutPage.cs b/ILSpy/AboutPage.cs index 85d2b794a..8451fa533 100644 --- a/ILSpy/AboutPage.cs +++ b/ILSpy/AboutPage.cs @@ -41,13 +41,10 @@ namespace ICSharpCode.ILSpy [ExportMainMenuCommand(Menu = nameof(Resources._Help), Header = nameof(Resources._About), MenuOrder = 99999)] sealed class AboutPage : SimpleCommand { - [Import] - DecompilerTextView decompilerTextView = null; - public override void Execute(object parameter) { MainWindow.Instance.UnselectAll(); - Display(decompilerTextView); + Display(Docking.DockWorkspace.Instance.GetTextView()); } static readonly Uri UpdateUrl = new Uri("https://ilspy.net/updates.xml"); diff --git a/ILSpy/App.xaml.cs b/ILSpy/App.xaml.cs index 1417af930..ec05fb882 100644 --- a/ILSpy/App.xaml.cs +++ b/ILSpy/App.xaml.cs @@ -244,7 +244,7 @@ namespace ICSharpCode.ILSpy } } } - ILSpy.MainWindow.Instance.TextView.ShowText(output); + Docking.DockWorkspace.Instance.ShowText(output); e.Handled = true; } } diff --git a/ILSpy/Commands/DecompileAllCommand.cs b/ILSpy/Commands/DecompileAllCommand.cs index 9cf8cbc11..ac263edf7 100644 --- a/ILSpy/Commands/DecompileAllCommand.cs +++ b/ILSpy/Commands/DecompileAllCommand.cs @@ -38,7 +38,7 @@ namespace ICSharpCode.ILSpy public override void Execute(object parameter) { - MainWindow.Instance.TextView.RunWithCancellation(ct => Task.Factory.StartNew(() => { + Docking.DockWorkspace.Instance.RunWithCancellation(ct => Task.Factory.StartNew(() => { AvalonEditTextOutput output = new AvalonEditTextOutput(); Parallel.ForEach(MainWindow.Instance.CurrentAssemblyList.GetAssemblies(), new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount, CancellationToken = ct }, delegate(LoadedAssembly asm) { if (!asm.HasLoadError) { @@ -64,7 +64,7 @@ namespace ICSharpCode.ILSpy } }); return output; - }, ct)).Then(output => MainWindow.Instance.TextView.ShowText(output)).HandleExceptions(); + }, ct)).Then(output => Docking.DockWorkspace.Instance.ShowText(output)).HandleExceptions(); } } @@ -77,7 +77,7 @@ namespace ICSharpCode.ILSpy var language = MainWindow.Instance.CurrentLanguage; var nodes = MainWindow.Instance.SelectedNodes.ToArray(); var options = new DecompilationOptions(); - MainWindow.Instance.TextView.RunWithCancellation(ct => Task.Factory.StartNew(() => { + Docking.DockWorkspace.Instance.RunWithCancellation(ct => Task.Factory.StartNew(() => { options.CancellationToken = ct; Stopwatch w = Stopwatch.StartNew(); for (int i = 0; i < numRuns; ++i) { @@ -90,7 +90,7 @@ namespace ICSharpCode.ILSpy double msPerRun = w.Elapsed.TotalMilliseconds / numRuns; output.Write($"Average time: {msPerRun.ToString("f1")}ms\n"); return output; - }, ct)).Then(output => MainWindow.Instance.TextView.ShowText(output)).HandleExceptions(); + }, ct)).Then(output => Docking.DockWorkspace.Instance.ShowText(output)).HandleExceptions(); } } } diff --git a/ILSpy/Commands/DecompileInNewViewCommand.cs b/ILSpy/Commands/DecompileInNewViewCommand.cs index 2a1119fe3..e5ca26f03 100644 --- a/ILSpy/Commands/DecompileInNewViewCommand.cs +++ b/ILSpy/Commands/DecompileInNewViewCommand.cs @@ -16,6 +16,7 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. +using System; using System.Linq; using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.Properties; @@ -24,7 +25,7 @@ using ICSharpCode.ILSpy.TreeNodes; namespace ICSharpCode.ILSpy.Commands { - // [ExportContextMenuEntry(Header = nameof(Resources.DecompileToNewPanel), Icon = "images/Search", Category = nameof(Resources.Analyze), Order = 90)] + [ExportContextMenuEntry(Header = nameof(Resources.DecompileToNewPanel), Icon = "images/Search", Category = nameof(Resources.Analyze), Order = 90)] internal sealed class DecompileInNewViewCommand : IContextMenuEntry { public bool IsVisible(TextViewContext context) @@ -41,15 +42,15 @@ namespace ICSharpCode.ILSpy.Commands return true; } - public async void Execute(TextViewContext context) + public void Execute(TextViewContext context) { - var dtv = new DecompilerTextView(); var nodes = context.SelectedTreeNodes.Cast().ToArray(); var title = string.Join(", ", nodes.Select(x => x.ToString())); - // TODO - //MainWindow.Instance.ShowInNewPane(title, dtv, PanePosition.Document); - //DockWorkspace.Instance.Documents.Add(new ViewModels.DocumentModel() { Title = title }); - await dtv.DecompileAsync(MainWindow.Instance.CurrentLanguage, nodes, new DecompilationOptions()); + DockWorkspace.Instance.Documents.Add(new ViewModels.DecompiledDocumentModel(title, title)); + DockWorkspace.Instance.ActiveDocument = DockWorkspace.Instance.Documents.Last(); + MainWindow.Instance.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Background, (Action)(delegate { + DockWorkspace.Instance.GetTextView().DecompileAsync(MainWindow.Instance.CurrentLanguage, nodes, new DecompilationOptions()); + })); } } } diff --git a/ILSpy/Commands/DisassembleAllCommand.cs b/ILSpy/Commands/DisassembleAllCommand.cs index 74af340a1..23319be78 100644 --- a/ILSpy/Commands/DisassembleAllCommand.cs +++ b/ILSpy/Commands/DisassembleAllCommand.cs @@ -35,7 +35,7 @@ namespace ICSharpCode.ILSpy public override void Execute(object parameter) { - MainWindow.Instance.TextView.RunWithCancellation(ct => Task.Factory.StartNew(() => { + Docking.DockWorkspace.Instance.RunWithCancellation(ct => Task.Factory.StartNew(() => { AvalonEditTextOutput output = new AvalonEditTextOutput(); Parallel.ForEach(MainWindow.Instance.CurrentAssemblyList.GetAssemblies(), new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount, CancellationToken = ct }, delegate(LoadedAssembly asm) { if (!asm.HasLoadError) { @@ -61,7 +61,7 @@ namespace ICSharpCode.ILSpy } }); return output; - }, ct)).Then(output => MainWindow.Instance.TextView.ShowText(output)).HandleExceptions(); + }, ct)).Then(output => Docking.DockWorkspace.Instance.ShowText(output)).HandleExceptions(); } } } diff --git a/ILSpy/Commands/GeneratePdbContextMenuEntry.cs b/ILSpy/Commands/GeneratePdbContextMenuEntry.cs index a632ee27a..de254cfd4 100644 --- a/ILSpy/Commands/GeneratePdbContextMenuEntry.cs +++ b/ILSpy/Commands/GeneratePdbContextMenuEntry.cs @@ -64,7 +64,7 @@ namespace ICSharpCode.ILSpy if (dlg.ShowDialog() != true) return; DecompilationOptions options = new DecompilationOptions(); string fileName = dlg.FileName; - MainWindow.Instance.TextView.RunWithCancellation(ct => Task.Factory.StartNew(() => { + Docking.DockWorkspace.Instance.RunWithCancellation(ct => Task.Factory.StartNew(() => { AvalonEditTextOutput output = new AvalonEditTextOutput(); Stopwatch stopwatch = Stopwatch.StartNew(); using (FileStream stream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write)) { @@ -83,7 +83,7 @@ namespace ICSharpCode.ILSpy output.AddButton(null, "Open Explorer", delegate { Process.Start("explorer", "/select,\"" + fileName + "\""); }); output.WriteLine(); return output; - }, ct)).Then(output => MainWindow.Instance.TextView.ShowText(output)).HandleExceptions(); + }, ct)).Then(output => Docking.DockWorkspace.Instance.ShowText(output)).HandleExceptions(); } } diff --git a/ILSpy/Commands/Pdb2XmlCommand.cs b/ILSpy/Commands/Pdb2XmlCommand.cs index 96932a1d9..91b481f7b 100644 --- a/ILSpy/Commands/Pdb2XmlCommand.cs +++ b/ILSpy/Commands/Pdb2XmlCommand.cs @@ -49,7 +49,7 @@ namespace ICSharpCode.ILSpy { var highlighting = HighlightingManager.Instance.GetDefinitionByExtension(".xml"); var options = PdbToXmlOptions.IncludeEmbeddedSources | PdbToXmlOptions.IncludeMethodSpans | PdbToXmlOptions.IncludeTokens; - MainWindow.Instance.TextView.RunWithCancellation(ct => Task.Factory.StartNew(() => { + Docking.DockWorkspace.Instance.RunWithCancellation(ct => Task.Factory.StartNew(() => { AvalonEditTextOutput output = new AvalonEditTextOutput(); var writer = new TextOutputWriter(output); foreach (var node in nodes) { @@ -60,7 +60,7 @@ namespace ICSharpCode.ILSpy PdbToXmlConverter.ToXml(writer, pdbStream, peStream, options); } return output; - }, ct)).Then(output => MainWindow.Instance.TextView.ShowNodes(output, null, highlighting)).HandleExceptions(); + }, ct)).Then(output => Docking.DockWorkspace.Instance.ShowNodes(output, null, highlighting)).HandleExceptions(); } } diff --git a/ILSpy/Commands/SaveCodeContextMenuEntry.cs b/ILSpy/Commands/SaveCodeContextMenuEntry.cs index 3715b588d..e8cf4c4ac 100644 --- a/ILSpy/Commands/SaveCodeContextMenuEntry.cs +++ b/ILSpy/Commands/SaveCodeContextMenuEntry.cs @@ -55,7 +55,7 @@ namespace ICSharpCode.ILSpy.TextView public static void Execute(IReadOnlyList selectedNodes) { var currentLanguage = MainWindow.Instance.CurrentLanguage; - var textView = MainWindow.Instance.TextView; + var textView = Docking.DockWorkspace.Instance.GetTextView(); if (selectedNodes.Count == 1 && selectedNodes[0] is ILSpyTreeNode singleSelection) { // if there's only one treenode selected // we will invoke the custom Save logic diff --git a/ILSpy/ContextMenuEntry.cs b/ILSpy/ContextMenuEntry.cs index d04155f43..c6325650d 100644 --- a/ILSpy/ContextMenuEntry.cs +++ b/ILSpy/ContextMenuEntry.cs @@ -126,19 +126,22 @@ namespace ICSharpCode.ILSpy /// /// Enables extensible context menu support for the specified tree view. /// - public static void Add(SharpTreeView treeView, DecompilerTextView textView = null) + public static void Add(SharpTreeView treeView) { - var provider = new ContextMenuProvider(treeView, textView); + var provider = new ContextMenuProvider(treeView); treeView.ContextMenuOpening += provider.treeView_ContextMenuOpening; // Context menu is shown only when the ContextMenu property is not null before the // ContextMenuOpening event handler is called. treeView.ContextMenu = new ContextMenu(); - if (textView != null) { - textView.ContextMenuOpening += provider.textView_ContextMenuOpening; - // Context menu is shown only when the ContextMenu property is not null before the - // ContextMenuOpening event handler is called. - textView.ContextMenu = new ContextMenu(); - } + } + + public static void Add(DecompilerTextView textView) + { + var provider = new ContextMenuProvider(textView); + textView.ContextMenuOpening += provider.textView_ContextMenuOpening; + // Context menu is shown only when the ContextMenu property is not null before the + // ContextMenuOpening event handler is called. + textView.ContextMenu = new ContextMenu(); } public static void Add(ListBox listBox) @@ -157,16 +160,23 @@ namespace ICSharpCode.ILSpy { entries = App.ExportProvider.GetExports().ToArray(); } + + ContextMenuProvider(DecompilerTextView textView) + : this() + { + this.textView = textView ?? throw new ArgumentNullException(nameof(textView)); + } - ContextMenuProvider(SharpTreeView treeView, DecompilerTextView textView = null) : this() + ContextMenuProvider(SharpTreeView treeView) + : this() { - this.treeView = treeView; - this.textView = textView; + this.treeView = treeView ?? throw new ArgumentNullException(nameof(treeView)); } - ContextMenuProvider(ListBox listBox) : this() + ContextMenuProvider(ListBox listBox) + : this() { - this.listBox = listBox; + this.listBox = listBox ?? throw new ArgumentNullException(nameof(listBox)); } void treeView_ContextMenuOpening(object sender, ContextMenuEventArgs e) diff --git a/ILSpy/DebugSteps.xaml.cs b/ILSpy/DebugSteps.xaml.cs index 12cb5f807..71c4f448e 100644 --- a/ILSpy/DebugSteps.xaml.cs +++ b/ILSpy/DebugSteps.xaml.cs @@ -123,8 +123,8 @@ namespace ICSharpCode.ILSpy { lastSelectedStep = step; var window = MainWindow.Instance; - var state = window.TextView.GetState(); - window.TextView.DecompileAsync(window.CurrentLanguage, window.SelectedNodes, + var state = DockWorkspace.Instance.GetState(); + DockWorkspace.Instance.GetTextView().DecompileAsync(window.CurrentLanguage, window.SelectedNodes, new DecompilationOptions(window.CurrentLanguageVersion) { StepLimit = step, IsDebug = isDebug, diff --git a/ILSpy/Docking/DockWorkspace.cs b/ILSpy/Docking/DockWorkspace.cs index 71999a01b..1735507f7 100644 --- a/ILSpy/Docking/DockWorkspace.cs +++ b/ILSpy/Docking/DockWorkspace.cs @@ -1,5 +1,10 @@ -using System.Collections.ObjectModel; +using System; +using System.Collections.ObjectModel; using System.ComponentModel; +using System.Threading; +using System.Threading.Tasks; +using ICSharpCode.AvalonEdit.Highlighting; +using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.ViewModels; namespace ICSharpCode.ILSpy.Docking @@ -41,5 +46,30 @@ namespace ICSharpCode.ILSpy.Docking { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } + + public void ShowText(AvalonEditTextOutput textOutput) + { + GetTextView().ShowText(textOutput); + } + + public DecompilerTextView GetTextView() + { + return ((DecompiledDocumentModel)ActiveDocument).TextView; + } + + public DecompilerTextViewState GetState() + { + return GetTextView().GetState(); + } + + public Task RunWithCancellation(Func> taskCreation) + { + return GetTextView().RunWithCancellation(taskCreation); + } + + internal void ShowNodes(AvalonEditTextOutput output, TreeNodes.ILSpyTreeNode[] nodes, IHighlightingDefinition highlighting) + { + GetTextView().ShowNodes(output, nodes, highlighting); + } } } diff --git a/ILSpy/MainWindow.xaml b/ILSpy/MainWindow.xaml index eaf340173..275419fa9 100644 --- a/ILSpy/MainWindow.xaml +++ b/ILSpy/MainWindow.xaml @@ -5,9 +5,10 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:tv="clr-namespace:ICSharpCode.TreeView;assembly=ICSharpCode.TreeView" xmlns:local="clr-namespace:ICSharpCode.ILSpy" xmlns:avalondock="http://schemas.xceed.com/wpf/xaml/avalondock" + xmlns:controls="clr-namespace:ICSharpCode.ILSpy.Controls" xmlns:avalondockproperties="clr-namespace:Xceed.Wpf.AvalonDock.Properties;assembly=Xceed.Wpf.AvalonDock" xmlns:docking="clr-namespace:ICSharpCode.ILSpy.Docking" - xmlns:controls="clr-namespace:ICSharpCode.ILSpy.Controls" + xmlns:textview="clr-namespace:ICSharpCode.ILSpy.TextView" xmlns:analyzers="clr-namespace:ICSharpCode.ILSpy.Analyzers" xmlns:properties="clr-namespace:ICSharpCode.ILSpy.Properties" xmlns:viewmodels="clr-namespace:ICSharpCode.ILSpy.ViewModels" @@ -58,8 +59,7 @@ - - + @@ -165,300 +165,8 @@ DataContext="{Binding Workspace}" AnchorablesSource="{Binding ToolPanes}" DocumentsSource="{Binding Documents}" - ActiveContent="{Binding ActiveDocument, Mode=Default, Converter={StaticResource ActiveDocumentConverter}}" + ActiveContent="{Binding ActiveDocument, Mode=TwoWay, Converter={StaticResource ActiveDocumentConverter}}" AllowMixedOrientation="True"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -482,7 +190,7 @@ - + @@ -490,12 +198,14 @@ - diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs index 3e05b0f2a..66053dfce 100644 --- a/ILSpy/MainWindow.xaml.cs +++ b/ILSpy/MainWindow.xaml.cs @@ -73,8 +73,6 @@ namespace ICSharpCode.ILSpy AssemblyList assemblyList; AssemblyListTreeNode assemblyListTreeNode; - readonly DecompilerTextView decompilerTextView; - static MainWindow instance; public static MainWindow Instance { @@ -126,16 +124,13 @@ namespace ICSharpCode.ILSpy InitializeComponent(); - decompilerTextView = App.ExportProvider.GetExportedValue(); - mainPane.Content = decompilerTextView; - sessionSettings.DockLayout.Deserialize(new XmlLayoutSerializer(DockManager)); sessionSettings.FilterSettings.PropertyChanged += filterSettings_PropertyChanged; InitMainMenu(); InitToolbar(); - ContextMenuProvider.Add(treeView, decompilerTextView); + ContextMenuProvider.Add(treeView); this.Loaded += MainWindow_Loaded; } @@ -376,7 +371,7 @@ namespace ICSharpCode.ILSpy if (!found && treeView.SelectedItem == initialSelection) { AvalonEditTextOutput output = new AvalonEditTextOutput(); output.Write(string.Format("Cannot find '{0}' in command line specified assemblies.", navigateTo)); - decompilerTextView.ShowText(output); + DockWorkspace.Instance.ShowText(output); } } else if (relevantAssemblies.Count == 1) { // NavigateTo == null and an assembly was given on the command-line: @@ -404,7 +399,7 @@ namespace ICSharpCode.ILSpy // only if not showing the about page, perform the update check: await ShowMessageIfUpdatesAvailableAsync(spySettings); } else { - AboutPage.Display(decompilerTextView); + AboutPage.Display(DockWorkspace.Instance.GetTextView()); } } } @@ -466,7 +461,8 @@ namespace ICSharpCode.ILSpy void MainWindow_Loaded(object sender, RoutedEventArgs e) { DockWorkspace.Instance.ToolPanes.Add(AssemblyListPaneModel.Instance); - DockWorkspace.Instance.Documents.Add(new DocumentModel()); + DockWorkspace.Instance.Documents.Add(new DecompiledDocumentModel() { IsCloseable = false }); + DockWorkspace.Instance.ActiveDocument = DockWorkspace.Instance.Documents.First(); ILSpySettings spySettings = this.spySettingsForMainWindow_Loaded; this.spySettingsForMainWindow_Loaded = null; @@ -504,7 +500,7 @@ namespace ICSharpCode.ILSpy AvalonEditTextOutput output = new AvalonEditTextOutput(); if (FormatExceptions(App.StartupExceptions.ToArray(), output)) - decompilerTextView.ShowText(output); + DockWorkspace.Instance.ShowText(output); } bool FormatExceptions(App.ExceptionData[] exceptions, ITextOutput output) @@ -931,8 +927,7 @@ namespace ICSharpCode.ILSpy { DecompileSelectedNodes(); - if (SelectionChanged != null) - SelectionChanged(sender, e); + SelectionChanged?.Invoke(sender, e); } Task decompilationTask; @@ -947,7 +942,7 @@ namespace ICSharpCode.ILSpy return; if (recordHistory) { - var dtState = decompilerTextView.GetState(); + var dtState = DockWorkspace.Instance.GetState(); if (dtState != null) history.UpdateCurrent(new NavigationState(dtState)); history.Record(new NavigationState(treeView.SelectedItems.OfType())); @@ -955,10 +950,10 @@ namespace ICSharpCode.ILSpy if (treeView.SelectedItems.Count == 1) { ILSpyTreeNode node = treeView.SelectedItem as ILSpyTreeNode; - if (node != null && node.View(decompilerTextView)) + if (node != null && node.View(DockWorkspace.Instance.GetTextView())) return; } - decompilationTask = decompilerTextView.DecompileAsync(this.CurrentLanguage, this.SelectedNodes, new DecompilationOptions() { TextViewState = state }); + decompilationTask = DockWorkspace.Instance.GetTextView().DecompileAsync(this.CurrentLanguage, this.SelectedNodes, new DecompilationOptions() { TextViewState = state }); } void SaveCommandCanExecute(object sender, CanExecuteRoutedEventArgs e) @@ -982,10 +977,6 @@ namespace ICSharpCode.ILSpy } } - public DecompilerTextView TextView { - get { return decompilerTextView; } - } - public Language CurrentLanguage => sessionSettings.FilterSettings.Language; public LanguageVersion CurrentLanguageVersion => sessionSettings.FilterSettings.LanguageVersion; @@ -1029,7 +1020,7 @@ namespace ICSharpCode.ILSpy void NavigateHistory(bool forward) { - var dtState = decompilerTextView.GetState(); + var dtState = DockWorkspace.Instance.GetState(); if (dtState != null) history.UpdateCurrent(new NavigationState(dtState)); var newState = forward ? history.GoForward() : history.GoBack(); diff --git a/ILSpy/TaskHelper.cs b/ILSpy/TaskHelper.cs index 8137ec152..bb76ffdbc 100644 --- a/ILSpy/TaskHelper.cs +++ b/ILSpy/TaskHelper.cs @@ -196,7 +196,7 @@ namespace ICSharpCode.ILSpy task.Catch(exception => MainWindow.Instance.Dispatcher.BeginInvoke(new Action(delegate { AvalonEditTextOutput output = new AvalonEditTextOutput(); output.Write(exception.ToString()); - MainWindow.Instance.TextView.ShowText(output); + Docking.DockWorkspace.Instance.ShowText(output); }))).IgnoreExceptions(); } } diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs index 52917540e..242e8bd47 100644 --- a/ILSpy/TextView/DecompilerTextView.cs +++ b/ILSpy/TextView/DecompilerTextView.cs @@ -53,6 +53,7 @@ using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.ILSpy.AvalonEdit; using ICSharpCode.ILSpy.Options; using ICSharpCode.ILSpy.TreeNodes; +using ICSharpCode.ILSpy.ViewModels; using Microsoft.Win32; namespace ICSharpCode.ILSpy.TextView @@ -61,7 +62,6 @@ namespace ICSharpCode.ILSpy.TextView /// Manages the TextEditor showing the decompiled code. /// Contains all the threading logic that makes the decompiler work in the background. /// - [Export, PartCreationPolicy(CreationPolicy.Shared)] public sealed partial class DecompilerTextView : UserControl, IDisposable { readonly ReferenceElementGenerator referenceElementGenerator; @@ -103,7 +103,7 @@ namespace ICSharpCode.ILSpy.TextView }); InitializeComponent(); - + this.referenceElementGenerator = new ReferenceElementGenerator(this.JumpToReference, this.IsLink); textEditor.TextArea.TextView.ElementGenerators.Add(referenceElementGenerator); this.uiElementGenerator = new UIElementGenerator(); @@ -140,6 +140,8 @@ namespace ICSharpCode.ILSpy.TextView // add marker service & margin textEditor.TextArea.TextView.BackgroundRenderers.Add(textMarkerService); textEditor.TextArea.TextView.LineTransformers.Add(textMarkerService); + + ContextMenuProvider.Add(this); } void RemoveEditCommand(RoutedUICommand command) @@ -1032,6 +1034,14 @@ namespace ICSharpCode.ILSpy.TextView } } #endregion + + private void self_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e) + { + if (e.OldValue is DecompiledDocumentModel oldModel) + oldModel.TextView = null; + if (e.NewValue is DecompiledDocumentModel newModel) + newModel.TextView = this; + } } public class DecompilerTextViewState diff --git a/ILSpy/TextView/DecompilerTextView.xaml b/ILSpy/TextView/DecompilerTextView.xaml index eed20cda4..fbeaf98d3 100644 --- a/ILSpy/TextView/DecompilerTextView.xaml +++ b/ILSpy/TextView/DecompilerTextView.xaml @@ -1,8 +1,9 @@  + xmlns:properties="clr-namespace:ICSharpCode.ILSpy.Properties" + xmlns:ae="clr-namespace:ICSharpCode.AvalonEdit;assembly=ICSharpCode.AvalonEdit" + DataContextChanged="self_DataContextChanged"> diff --git a/ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs b/ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs index ff57aa944..c13118e1e 100644 --- a/ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs +++ b/ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs @@ -65,7 +65,7 @@ namespace ICSharpCode.ILSpy.TreeNodes ISmartTextOutput smartOutput = output as ISmartTextOutput; if (smartOutput != null) { - smartOutput.AddButton(Images.Save, Resources.Save, delegate { Save(MainWindow.Instance.TextView); }); + smartOutput.AddButton(Images.Save, Resources.Save, delegate { Save(Docking.DockWorkspace.Instance.GetTextView()); }); output.WriteLine(); } } diff --git a/ILSpy/ViewModels/DocumentModel.cs b/ILSpy/ViewModels/DocumentModel.cs index 2fa9129ab..3e7fbeb8d 100644 --- a/ILSpy/ViewModels/DocumentModel.cs +++ b/ILSpy/ViewModels/DocumentModel.cs @@ -1,14 +1,40 @@ -namespace ICSharpCode.ILSpy.ViewModels +using System; +using ICSharpCode.ILSpy.TextView; + +namespace ICSharpCode.ILSpy.ViewModels { - public class DocumentModel : PaneModel + public abstract class DocumentModel : PaneModel { public override PanePosition DefaultPosition => PanePosition.Document; - public DocumentModel() + protected DocumentModel(string contentId, string title) + { + this.ContentId = contentId; + this.Title = title; + } + } + + public class DecompiledDocumentModel : DocumentModel + { + public DecompiledDocumentModel() + : base("//Decompiled", "View") { - ContentId = "document"; - Title = "View"; - IsCloseable = false; + } + + public DecompiledDocumentModel(string id, string title) + : base("//Decompiled/" + id, title) + { + } + + private DecompilerTextView textView; + public DecompilerTextView TextView { + get => textView; + set { + if (textView != value) { + textView = value; + RaisePropertyChanged(nameof(TextView)); + } + } } } } diff --git a/ILSpy/ViewModels/PaneModel.cs b/ILSpy/ViewModels/PaneModel.cs index bce2ecc70..61b753276 100644 --- a/ILSpy/ViewModels/PaneModel.cs +++ b/ILSpy/ViewModels/PaneModel.cs @@ -1,10 +1,38 @@ -using System.ComponentModel; +using System; +using System.ComponentModel; using System.Windows.Input; namespace ICSharpCode.ILSpy.ViewModels { public abstract class PaneModel : INotifyPropertyChanged { + class CloseCommandImpl : ICommand + { + readonly PaneModel model; + + public CloseCommandImpl(PaneModel model) + { + this.model = model; + } + + public event EventHandler CanExecuteChanged; + + public bool CanExecute(object parameter) + { + return model.IsCloseable; + } + + public void Execute(object parameter) + { + Docking.DockWorkspace.Instance.Remove(model); + } + } + + public PaneModel() + { + this.closeCommand = new CloseCommandImpl(this); + } + public abstract PanePosition DefaultPosition { get; } public event PropertyChangedEventHandler PropertyChanged; @@ -58,6 +86,17 @@ namespace ICSharpCode.ILSpy.ViewModels } } + private ICommand closeCommand; + public ICommand CloseCommand { + get { return closeCommand; } + set { + if (closeCommand != value) { + closeCommand = value; + RaisePropertyChanged(nameof(CloseCommand)); + } + } + } + private string contentId; public string ContentId { get => contentId; From 2be6d279b366a3619dc75d07b0718535178fb1c4 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 16 Nov 2019 13:57:09 +0100 Subject: [PATCH 05/12] Fix update-assemblyinfo.ps1 for worktrees --- BuildTools/update-assemblyinfo.ps1 | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/BuildTools/update-assemblyinfo.ps1 b/BuildTools/update-assemblyinfo.ps1 index 7e14e23da..f021a331d 100644 --- a/BuildTools/update-assemblyinfo.ps1 +++ b/BuildTools/update-assemblyinfo.ps1 @@ -9,11 +9,11 @@ $masterBranches = @("master", "5.0.x"); $globalAssemblyInfoTemplateFile = "ILSpy/Properties/AssemblyInfo.template.cs"; function Test-File([string]$filename) { - return [System.IO.File]::Exists( (Join-Path (Get-Location) $filename) ); + return [System.IO.File]::Exists((Join-Path (Get-Location) $filename)); } function Test-Dir([string]$name) { - return [System.IO.Directory]::Exists( (Join-Path (Get-Location) $name) ); + return [System.IO.Directory]::Exists((Join-Path (Get-Location) $name)); } function Find-Git() { @@ -38,22 +38,26 @@ function Find-Git() { return $false; } +function No-Git() { + return -not (((Test-Dir ".git") -or (Test-File ".git")) -and (Find-Git)); +} + function gitVersion() { - if (-not ((Test-Dir ".git") -and (Find-Git))) { + if (No-Git) { return 0; } return [Int32]::Parse((git rev-list --count "$baseCommit..HEAD")) + $baseCommitRev; } function gitCommitHash() { - if (-not ((Test-Dir ".git") -and (Find-Git))) { + if (No-Git) { return "0000000000000000000000000000000000000000"; } return (git rev-list "$baseCommit..HEAD") | Select -First 1; } function gitBranch() { - if (-not ((Test-Dir ".git" -or Test-File ".git") -and (Find-Git))) { + if (No-Git) { return "no-branch"; } From aa5258ce0f92d60f35f389b359be407d50c7b341 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 16 Nov 2019 19:28:23 +0100 Subject: [PATCH 06/12] Make header of active document bold. --- ILSpy/MainWindow.xaml | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/ILSpy/MainWindow.xaml b/ILSpy/MainWindow.xaml index 275419fa9..9b1aee398 100644 --- a/ILSpy/MainWindow.xaml +++ b/ILSpy/MainWindow.xaml @@ -162,11 +162,11 @@ + DataContext="{Binding Workspace}" + AnchorablesSource="{Binding ToolPanes}" + DocumentsSource="{Binding Documents}" + ActiveContent="{Binding ActiveDocument, Mode=TwoWay, Converter={StaticResource ActiveDocumentConverter}}" + AllowMixedOrientation="True"> @@ -178,6 +178,17 @@ + + + + + + + + + + + @@ -216,6 +227,7 @@ + From 004a585efc5532c2dfc119d234f540c023a592e5 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 16 Nov 2019 19:29:12 +0100 Subject: [PATCH 07/12] Allow ISmartTextOutput to set the title of the decompilation tab. --- ILSpy/ISmartTextOutput.cs | 5 +++++ ILSpy/TextView/AvalonEditTextOutput.cs | 2 ++ ILSpy/TextView/DecompilerTextView.cs | 7 +++++++ 3 files changed, 14 insertions(+) diff --git a/ILSpy/ISmartTextOutput.cs b/ILSpy/ISmartTextOutput.cs index d429a7ae5..62098956e 100644 --- a/ILSpy/ISmartTextOutput.cs +++ b/ILSpy/ISmartTextOutput.cs @@ -38,6 +38,11 @@ namespace ICSharpCode.ILSpy void BeginSpan(HighlightingColor highlightingColor); void EndSpan(); + + /// + /// Gets/sets the title displayed in the document tab's header. + /// + string Title { get; set; } } public static class SmartTextOutputExtensions diff --git a/ILSpy/TextView/AvalonEditTextOutput.cs b/ILSpy/TextView/AvalonEditTextOutput.cs index 6c03a8b2d..79f6698c8 100644 --- a/ILSpy/TextView/AvalonEditTextOutput.cs +++ b/ILSpy/TextView/AvalonEditTextOutput.cs @@ -81,6 +81,8 @@ namespace ICSharpCode.ILSpy.TextView bool needsIndent; public string IndentationString { get; set; } = "\t"; + + public string Title { get; set; } internal readonly List elementGenerators = new List(); diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs index 242e8bd47..888fd865d 100644 --- a/ILSpy/TextView/DecompilerTextView.cs +++ b/ILSpy/TextView/DecompilerTextView.cs @@ -629,6 +629,10 @@ namespace ICSharpCode.ILSpy.TextView foldingStrategy.UpdateFoldings(foldingManager, textEditor.Document); Debug.WriteLine(" Updating folding: {0}", w.Elapsed); w.Restart(); } + + if (this.DataContext is PaneModel model) { + model.Title = textOutput.Title; + } } #endregion @@ -751,6 +755,9 @@ namespace ICSharpCode.ILSpy.TextView void DecompileNodes(DecompilationContext context, ITextOutput textOutput) { var nodes = context.TreeNodes; + if (textOutput is ISmartTextOutput smartTextOutput) { + smartTextOutput.Title = string.Join(", ", nodes.Select(n => n.ToString())); + } for (int i = 0; i < nodes.Length; i++) { if (i > 0) textOutput.WriteLine(); From 18f0038b293aaaebe6d2f80a7001d17cd0f0d682 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 16 Nov 2019 19:48:57 +0100 Subject: [PATCH 08/12] Set title in AboutPage --- ILSpy/AboutPage.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ILSpy/AboutPage.cs b/ILSpy/AboutPage.cs index 8451fa533..c2219e8a5 100644 --- a/ILSpy/AboutPage.cs +++ b/ILSpy/AboutPage.cs @@ -54,7 +54,7 @@ namespace ICSharpCode.ILSpy public static void Display(DecompilerTextView textView) { - AvalonEditTextOutput output = new AvalonEditTextOutput() { EnableHyperlinks = true }; + AvalonEditTextOutput output = new AvalonEditTextOutput() { Title = Resources._About, EnableHyperlinks = true }; output.WriteLine(Resources.ILSpyVersion + RevisionClass.FullVersion); if(WindowsVersionHelper.HasPackageIdentity) { output.WriteLine($"Package Name: {WindowsVersionHelper.GetPackageFamilyName()}"); From 388c8f611cbf6a83432fa12a512e2ce26c73ca83 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 16 Nov 2019 19:49:26 +0100 Subject: [PATCH 09/12] Add DecompileInNewViewCommand to TextView context menu. --- ILSpy/Commands/DecompileInNewViewCommand.cs | 27 ++++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/ILSpy/Commands/DecompileInNewViewCommand.cs b/ILSpy/Commands/DecompileInNewViewCommand.cs index e5ca26f03..92fdd7275 100644 --- a/ILSpy/Commands/DecompileInNewViewCommand.cs +++ b/ILSpy/Commands/DecompileInNewViewCommand.cs @@ -18,6 +18,7 @@ using System; using System.Linq; +using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.TextView; @@ -30,27 +31,35 @@ namespace ICSharpCode.ILSpy.Commands { public bool IsVisible(TextViewContext context) { - if (context.SelectedTreeNodes == null) - return false; - return true; + return context.SelectedTreeNodes != null || context.Reference?.Reference is IEntity; } public bool IsEnabled(TextViewContext context) { - if (context.SelectedTreeNodes == null) - return false; - return true; + return context.SelectedTreeNodes != null || context.Reference?.Reference is IEntity; } public void Execute(TextViewContext context) { - var nodes = context.SelectedTreeNodes.Cast().ToArray(); + if (context.SelectedTreeNodes != null) { + var nodes = context.SelectedTreeNodes.Cast().ToArray(); + DecompileNodes(nodes); + } else if (context.Reference?.Reference is IEntity entity) { + var node = MainWindow.Instance.FindTreeNode(entity); + if (node != null) { + DecompileNodes(node); + } + } + } + + private static void DecompileNodes(params ILSpyTreeNode[] nodes) + { var title = string.Join(", ", nodes.Select(x => x.ToString())); DockWorkspace.Instance.Documents.Add(new ViewModels.DecompiledDocumentModel(title, title)); DockWorkspace.Instance.ActiveDocument = DockWorkspace.Instance.Documents.Last(); - MainWindow.Instance.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Background, (Action)(delegate { + MainWindow.Instance.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Background, (Action)delegate { DockWorkspace.Instance.GetTextView().DecompileAsync(MainWindow.Instance.CurrentLanguage, nodes, new DecompilationOptions()); - })); + }); } } } From c84f220338c52bd87125205921c05e44b8282616 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 16 Nov 2019 22:14:52 +0100 Subject: [PATCH 10/12] Enable separate language (version) settings per document. --- ILSpy/Commands/DecompileInNewViewCommand.cs | 2 +- ILSpy/Docking/DockWorkspace.cs | 25 ++++++++++++++++++++- ILSpy/MainWindow.xaml.cs | 4 +++- ILSpy/ViewModels/DocumentModel.cs | 24 +++++++++++++++++++- 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/ILSpy/Commands/DecompileInNewViewCommand.cs b/ILSpy/Commands/DecompileInNewViewCommand.cs index 92fdd7275..94e81d360 100644 --- a/ILSpy/Commands/DecompileInNewViewCommand.cs +++ b/ILSpy/Commands/DecompileInNewViewCommand.cs @@ -55,7 +55,7 @@ namespace ICSharpCode.ILSpy.Commands private static void DecompileNodes(params ILSpyTreeNode[] nodes) { var title = string.Join(", ", nodes.Select(x => x.ToString())); - DockWorkspace.Instance.Documents.Add(new ViewModels.DecompiledDocumentModel(title, title)); + DockWorkspace.Instance.Documents.Add(new ViewModels.DecompiledDocumentModel(title, title) { Language = MainWindow.Instance.CurrentLanguage, LanguageVersion = MainWindow.Instance.CurrentLanguageVersion }); DockWorkspace.Instance.ActiveDocument = DockWorkspace.Instance.Documents.Last(); MainWindow.Instance.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Background, (Action)delegate { DockWorkspace.Instance.GetTextView().DecompileAsync(MainWindow.Instance.CurrentLanguage, nodes, new DecompilationOptions()); diff --git a/ILSpy/Docking/DockWorkspace.cs b/ILSpy/Docking/DockWorkspace.cs index 1735507f7..a75ef21a2 100644 --- a/ILSpy/Docking/DockWorkspace.cs +++ b/ILSpy/Docking/DockWorkspace.cs @@ -1,6 +1,7 @@ using System; using System.Collections.ObjectModel; using System.ComponentModel; +using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using ICSharpCode.AvalonEdit.Highlighting; @@ -11,6 +12,8 @@ namespace ICSharpCode.ILSpy.Docking { public class DockWorkspace : INotifyPropertyChanged { + private SessionSettings sessionSettings; + public event PropertyChangedEventHandler PropertyChanged; public static DockWorkspace Instance { get; } = new DockWorkspace(); @@ -37,12 +40,16 @@ namespace ICSharpCode.ILSpy.Docking set { if (_activeDocument != value) { _activeDocument = value; + if (value is DecompiledDocumentModel ddm) { + this.sessionSettings.FilterSettings.Language = ddm.Language; + this.sessionSettings.FilterSettings.LanguageVersion = ddm.LanguageVersion; + } RaisePropertyChanged(nameof(ActiveDocument)); } } } - protected void RaisePropertyChanged(string propertyName) + protected void RaisePropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } @@ -71,5 +78,21 @@ namespace ICSharpCode.ILSpy.Docking { GetTextView().ShowNodes(output, nodes, highlighting); } + + internal void LoadSettings(SessionSettings sessionSettings) + { + this.sessionSettings = sessionSettings; + sessionSettings.FilterSettings.PropertyChanged += FilterSettings_PropertyChanged; + } + + private void FilterSettings_PropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (ActiveDocument is DecompiledDocumentModel ddm) { + if (e.PropertyName == "Language" || e.PropertyName == "LanguageVersion") { + ddm.Language = sessionSettings.FilterSettings.Language; + ddm.LanguageVersion = sessionSettings.FilterSettings.LanguageVersion; + } + } + } } } diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs index 66053dfce..cf9c803c8 100644 --- a/ILSpy/MainWindow.xaml.cs +++ b/ILSpy/MainWindow.xaml.cs @@ -122,6 +122,8 @@ namespace ICSharpCode.ILSpy SessionSettings = sessionSettings }; + DockWorkspace.Instance.LoadSettings(sessionSettings); + InitializeComponent(); sessionSettings.DockLayout.Deserialize(new XmlLayoutSerializer(DockManager)); @@ -461,7 +463,7 @@ namespace ICSharpCode.ILSpy void MainWindow_Loaded(object sender, RoutedEventArgs e) { DockWorkspace.Instance.ToolPanes.Add(AssemblyListPaneModel.Instance); - DockWorkspace.Instance.Documents.Add(new DecompiledDocumentModel() { IsCloseable = false }); + DockWorkspace.Instance.Documents.Add(new DecompiledDocumentModel() { IsCloseable = false, Language = CurrentLanguage, LanguageVersion = CurrentLanguageVersion }); DockWorkspace.Instance.ActiveDocument = DockWorkspace.Instance.Documents.First(); ILSpySettings spySettings = this.spySettingsForMainWindow_Loaded; diff --git a/ILSpy/ViewModels/DocumentModel.cs b/ILSpy/ViewModels/DocumentModel.cs index 3e7fbeb8d..b3139f3d5 100644 --- a/ILSpy/ViewModels/DocumentModel.cs +++ b/ILSpy/ViewModels/DocumentModel.cs @@ -36,5 +36,27 @@ namespace ICSharpCode.ILSpy.ViewModels } } } + + private Language language; + public Language Language { + get => language; + set { + if (language != value) { + language = value; + RaisePropertyChanged(nameof(Language)); + } + } + } + + private LanguageVersion languageVersion; + public LanguageVersion LanguageVersion { + get => languageVersion; + set { + if (languageVersion != value) { + languageVersion = value; + RaisePropertyChanged(nameof(LanguageVersion)); + } + } + } } -} +} \ No newline at end of file From 2911cb221560651113bc307afcaf49423f4926de Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 17 Nov 2019 08:45:30 +0100 Subject: [PATCH 11/12] Add license headers to newly added files. --- ILSpy/Docking/ActiveDocumentConverter.cs | 20 +++++++++++++++++++- ILSpy/Docking/DockLayoutSettings.cs | 20 +++++++++++++++++++- ILSpy/Docking/DockWorkspace.cs | 20 +++++++++++++++++++- ILSpy/Docking/LayoutUpdateStrategy.cs | 20 +++++++++++++++++++- ILSpy/Docking/PaneCollection.cs | 20 +++++++++++++++++++- ILSpy/Docking/PanePosition.cs | 20 +++++++++++++++++++- ILSpy/Docking/PaneStyleSelector.cs | 17 +++++++++++++++++ ILSpy/Docking/PaneTemplateSelector.cs | 20 +++++++++++++++++++- 8 files changed, 150 insertions(+), 7 deletions(-) diff --git a/ILSpy/Docking/ActiveDocumentConverter.cs b/ILSpy/Docking/ActiveDocumentConverter.cs index 326d72ae2..77a634474 100644 --- a/ILSpy/Docking/ActiveDocumentConverter.cs +++ b/ILSpy/Docking/ActiveDocumentConverter.cs @@ -1,4 +1,22 @@ -using System; +// 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.Windows.Data; using ICSharpCode.ILSpy.ViewModels; diff --git a/ILSpy/Docking/DockLayoutSettings.cs b/ILSpy/Docking/DockLayoutSettings.cs index 69ca8c541..23588db97 100644 --- a/ILSpy/Docking/DockLayoutSettings.cs +++ b/ILSpy/Docking/DockLayoutSettings.cs @@ -1,4 +1,22 @@ -using System; +// Copyright (c) 2019 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.IO; using System.Linq; using System.Xml; diff --git a/ILSpy/Docking/DockWorkspace.cs b/ILSpy/Docking/DockWorkspace.cs index a75ef21a2..aec46085a 100644 --- a/ILSpy/Docking/DockWorkspace.cs +++ b/ILSpy/Docking/DockWorkspace.cs @@ -1,4 +1,22 @@ -using System; +// Copyright (c) 2019 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.ComponentModel; using System.Runtime.CompilerServices; diff --git a/ILSpy/Docking/LayoutUpdateStrategy.cs b/ILSpy/Docking/LayoutUpdateStrategy.cs index 751e6abde..478a92c09 100644 --- a/ILSpy/Docking/LayoutUpdateStrategy.cs +++ b/ILSpy/Docking/LayoutUpdateStrategy.cs @@ -1,4 +1,22 @@ -using System; +// Copyright (c) 2019 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.Linq; using System.Windows; using System.Windows.Controls; diff --git a/ILSpy/Docking/PaneCollection.cs b/ILSpy/Docking/PaneCollection.cs index dfb9fd744..945740791 100644 --- a/ILSpy/Docking/PaneCollection.cs +++ b/ILSpy/Docking/PaneCollection.cs @@ -1,4 +1,22 @@ -using System.Collections; +// Copyright (c) 2019 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.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; diff --git a/ILSpy/Docking/PanePosition.cs b/ILSpy/Docking/PanePosition.cs index 719bcb44c..7ebb1b72a 100644 --- a/ILSpy/Docking/PanePosition.cs +++ b/ILSpy/Docking/PanePosition.cs @@ -1,4 +1,22 @@ -namespace ICSharpCode.ILSpy +// Copyright (c) 2019 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. + +namespace ICSharpCode.ILSpy { public enum PanePosition { diff --git a/ILSpy/Docking/PaneStyleSelector.cs b/ILSpy/Docking/PaneStyleSelector.cs index c805066e6..0d92b559a 100644 --- a/ILSpy/Docking/PaneStyleSelector.cs +++ b/ILSpy/Docking/PaneStyleSelector.cs @@ -1,6 +1,23 @@ using System.Windows; using System.Windows.Controls; using ICSharpCode.ILSpy.ViewModels; +// Copyright (c) 2019 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. namespace ICSharpCode.ILSpy.Docking { diff --git a/ILSpy/Docking/PaneTemplateSelector.cs b/ILSpy/Docking/PaneTemplateSelector.cs index ad94e8d8d..06b299b8e 100644 --- a/ILSpy/Docking/PaneTemplateSelector.cs +++ b/ILSpy/Docking/PaneTemplateSelector.cs @@ -1,4 +1,22 @@ -using System; +// Copyright (c) 2019 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.Linq; using System.Windows; From 2ae91559be619caa38b2dad96c02f382b381aaea Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 17 Nov 2019 19:27:00 +0100 Subject: [PATCH 12/12] Update Resources used in new panels + code cleanup. --- ILSpy/AboutPage.cs | 2 +- ILSpy/Docking/ActiveDocumentConverter.cs | 2 +- ILSpy/MainWindow.xaml.cs | 5 ----- ILSpy/Properties/Resources.Designer.cs | 18 +++++++++++++++++ ILSpy/Properties/Resources.resx | 6 ++++++ ILSpy/Properties/Resources.zh-Hans.resx | 3 +++ ILSpy/ViewModels/AnalyzerPaneModel.cs | 20 ++++++++++++++++++- ILSpy/ViewModels/AssemblyListPaneModel.cs | 24 +++++++++++++++++++++-- ILSpy/ViewModels/DebugStepsPaneModel.cs | 20 ++++++++++++++++++- ILSpy/ViewModels/DocumentModel.cs | 22 +++++++++++++++++++-- ILSpy/ViewModels/PaneModel.cs | 20 ++++++++++++++++++- ILSpy/ViewModels/SearchPaneModel.cs | 20 ++++++++++++++++++- ILSpy/ViewModels/ToolPaneModel.cs | 20 ++++++++++++++++++- 13 files changed, 166 insertions(+), 16 deletions(-) diff --git a/ILSpy/AboutPage.cs b/ILSpy/AboutPage.cs index c2219e8a5..7b966da95 100644 --- a/ILSpy/AboutPage.cs +++ b/ILSpy/AboutPage.cs @@ -54,7 +54,7 @@ namespace ICSharpCode.ILSpy public static void Display(DecompilerTextView textView) { - AvalonEditTextOutput output = new AvalonEditTextOutput() { Title = Resources._About, EnableHyperlinks = true }; + AvalonEditTextOutput output = new AvalonEditTextOutput() { Title = Resources.About, EnableHyperlinks = true }; output.WriteLine(Resources.ILSpyVersion + RevisionClass.FullVersion); if(WindowsVersionHelper.HasPackageIdentity) { output.WriteLine($"Package Name: {WindowsVersionHelper.GetPackageFamilyName()}"); diff --git a/ILSpy/Docking/ActiveDocumentConverter.cs b/ILSpy/Docking/ActiveDocumentConverter.cs index 77a634474..072f5e39a 100644 --- a/ILSpy/Docking/ActiveDocumentConverter.cs +++ b/ILSpy/Docking/ActiveDocumentConverter.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team +// Copyright (c) 2019 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 diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs index cf9c803c8..64f787a5a 100644 --- a/ILSpy/MainWindow.xaml.cs +++ b/ILSpy/MainWindow.xaml.cs @@ -1097,10 +1097,5 @@ namespace ICSharpCode.ILSpy { return toolBar.Items; } - - private void DockManager_DocumentClosed(object sender, Xceed.Wpf.AvalonDock.DocumentClosedEventArgs e) - { - - } } } diff --git a/ILSpy/Properties/Resources.Designer.cs b/ILSpy/Properties/Resources.Designer.cs index dd8e2a829..8b6d01b8a 100644 --- a/ILSpy/Properties/Resources.Designer.cs +++ b/ILSpy/Properties/Resources.Designer.cs @@ -267,6 +267,15 @@ namespace ICSharpCode.ILSpy.Properties { } } + /// + /// Looks up a localized string similar to About. + /// + public static string About { + get { + return ResourceManager.GetString("About", resourceCulture); + } + } + /// /// Looks up a localized string similar to |All Files|*.*. /// @@ -303,6 +312,15 @@ namespace ICSharpCode.ILSpy.Properties { } } + /// + /// Looks up a localized string similar to Assemblies. + /// + public static string Assemblies { + get { + return ResourceManager.GetString("Assemblies", resourceCulture); + } + } + /// /// Looks up a localized string similar to Assembly. /// diff --git a/ILSpy/Properties/Resources.resx b/ILSpy/Properties/Resources.resx index 7aa7db1df..92bb623ca 100644 --- a/ILSpy/Properties/Resources.resx +++ b/ILSpy/Properties/Resources.resx @@ -775,4 +775,10 @@ Are you sure you want to continue? Detect awaited using and foreach statements + + About + + + Assemblies + \ No newline at end of file diff --git a/ILSpy/Properties/Resources.zh-Hans.resx b/ILSpy/Properties/Resources.zh-Hans.resx index 4f04dba0b..0540d4faf 100644 --- a/ILSpy/Properties/Resources.zh-Hans.resx +++ b/ILSpy/Properties/Resources.zh-Hans.resx @@ -729,4 +729,7 @@ 搜索MSDN... + + 关于 + \ No newline at end of file diff --git a/ILSpy/ViewModels/AnalyzerPaneModel.cs b/ILSpy/ViewModels/AnalyzerPaneModel.cs index 0eaf9c818..bf7497c06 100644 --- a/ILSpy/ViewModels/AnalyzerPaneModel.cs +++ b/ILSpy/ViewModels/AnalyzerPaneModel.cs @@ -1,4 +1,22 @@ -namespace ICSharpCode.ILSpy.ViewModels +// Copyright (c) 2019 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. + +namespace ICSharpCode.ILSpy.ViewModels { public class AnalyzerPaneModel : ToolPaneModel { diff --git a/ILSpy/ViewModels/AssemblyListPaneModel.cs b/ILSpy/ViewModels/AssemblyListPaneModel.cs index 2d465a6a8..117b74796 100644 --- a/ILSpy/ViewModels/AssemblyListPaneModel.cs +++ b/ILSpy/ViewModels/AssemblyListPaneModel.cs @@ -1,4 +1,24 @@ -namespace ICSharpCode.ILSpy.ViewModels +// Copyright (c) 2019 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 ICSharpCode.ILSpy.Properties; + +namespace ICSharpCode.ILSpy.ViewModels { public class AssemblyListPaneModel : ToolPaneModel { @@ -10,7 +30,7 @@ private AssemblyListPaneModel() { - Title = "Assemblies"; + Title = Resources.Assemblies; ContentId = PaneContentId; IsCloseable = false; } diff --git a/ILSpy/ViewModels/DebugStepsPaneModel.cs b/ILSpy/ViewModels/DebugStepsPaneModel.cs index 196e9a7be..2ae7a6845 100644 --- a/ILSpy/ViewModels/DebugStepsPaneModel.cs +++ b/ILSpy/ViewModels/DebugStepsPaneModel.cs @@ -1,4 +1,22 @@ -namespace ICSharpCode.ILSpy.ViewModels +// Copyright (c) 2019 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. + +namespace ICSharpCode.ILSpy.ViewModels { public class DebugStepsPaneModel : ToolPaneModel { diff --git a/ILSpy/ViewModels/DocumentModel.cs b/ILSpy/ViewModels/DocumentModel.cs index b3139f3d5..47341cad6 100644 --- a/ILSpy/ViewModels/DocumentModel.cs +++ b/ILSpy/ViewModels/DocumentModel.cs @@ -1,4 +1,22 @@ -using System; +// Copyright (c) 2019 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 ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.TextView; namespace ICSharpCode.ILSpy.ViewModels @@ -17,7 +35,7 @@ namespace ICSharpCode.ILSpy.ViewModels public class DecompiledDocumentModel : DocumentModel { public DecompiledDocumentModel() - : base("//Decompiled", "View") + : base("//Decompiled", Resources.View) { } diff --git a/ILSpy/ViewModels/PaneModel.cs b/ILSpy/ViewModels/PaneModel.cs index 61b753276..dd6e12877 100644 --- a/ILSpy/ViewModels/PaneModel.cs +++ b/ILSpy/ViewModels/PaneModel.cs @@ -1,4 +1,22 @@ -using System; +// Copyright (c) 2019 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; using System.Windows.Input; diff --git a/ILSpy/ViewModels/SearchPaneModel.cs b/ILSpy/ViewModels/SearchPaneModel.cs index 2b3847817..ef8dce27c 100644 --- a/ILSpy/ViewModels/SearchPaneModel.cs +++ b/ILSpy/ViewModels/SearchPaneModel.cs @@ -1,4 +1,22 @@ -namespace ICSharpCode.ILSpy.ViewModels +// Copyright (c) 2019 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. + +namespace ICSharpCode.ILSpy.ViewModels { public class SearchPaneModel : ToolPaneModel { diff --git a/ILSpy/ViewModels/ToolPaneModel.cs b/ILSpy/ViewModels/ToolPaneModel.cs index e57a18067..8843fdd1a 100644 --- a/ILSpy/ViewModels/ToolPaneModel.cs +++ b/ILSpy/ViewModels/ToolPaneModel.cs @@ -1,4 +1,22 @@ -namespace ICSharpCode.ILSpy.ViewModels +// Copyright (c) 2019 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. + +namespace ICSharpCode.ILSpy.ViewModels { public abstract class ToolPaneModel : PaneModel {