Browse Source

Fix navigation and history in AboutPage

pull/1891/head
Siegfried Pammer 6 years ago
parent
commit
89e8ea072d
  1. 9
      ILSpy/AboutPage.cs
  2. 18
      ILSpy/App.xaml.cs
  3. 51
      ILSpy/MainWindow.xaml.cs
  4. 4
      ILSpy/Metadata/Helpers.cs
  5. 16
      ILSpy/NavigationState.cs
  6. 6
      ILSpy/TextView/AvalonEditTextOutput.cs
  7. 29
      ILSpy/TextView/DecompilerTextView.cs

9
ILSpy/AboutPage.cs

@ -18,7 +18,6 @@
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using System.ComponentModel.Composition;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
@ -28,14 +27,14 @@ using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Navigation;
using System.Xml.Linq; using System.Xml.Linq;
using ICSharpCode.AvalonEdit.Rendering; using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.ViewModels;
using ICSharpCode.ILSpy.Properties; using ICSharpCode.ILSpy.Properties;
using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TextView;
using OSVersionHelper; using OSVersionHelper;
namespace ICSharpCode.ILSpy namespace ICSharpCode.ILSpy
@ -45,8 +44,7 @@ namespace ICSharpCode.ILSpy
{ {
public override void Execute(object parameter) public override void Execute(object parameter)
{ {
MainWindow.Instance.UnselectAll(); MainWindow.Instance.NavigateTo(new RequestNavigateEventArgs(new Uri("resource://aboutpage"), null));
DockWorkspace.Instance.ActiveTabPage.ShowTextView(Display);
} }
static readonly Uri UpdateUrl = new Uri("https://ilspy.net/updates.xml"); static readonly Uri UpdateUrl = new Uri("https://ilspy.net/updates.xml");
@ -89,6 +87,7 @@ namespace ICSharpCode.ILSpy
foreach (var plugin in App.ExportProvider.GetExportedValues<IAboutPageAddition>()) foreach (var plugin in App.ExportProvider.GetExportedValues<IAboutPageAddition>())
plugin.Write(output); plugin.Write(output);
output.WriteLine(); output.WriteLine();
output.Address = new Uri("resource://AboutPage");
using (Stream s = typeof(AboutPage).Assembly.GetManifestResourceStream(typeof(AboutPage), "ILSpyAboutPage.txt")) { using (Stream s = typeof(AboutPage).Assembly.GetManifestResourceStream(typeof(AboutPage), "ILSpyAboutPage.txt")) {
using (StreamReader r = new StreamReader(s)) { using (StreamReader r = new StreamReader(s)) {
string line; string line;

18
ILSpy/App.xaml.cs

@ -22,17 +22,16 @@ using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Documents; using System.Windows.Documents;
using System.Windows.Navigation; using System.Windows.Navigation;
using System.Windows.Threading; using System.Windows.Threading;
using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.Options; using ICSharpCode.ILSpy.Options;
using Microsoft.VisualStudio.Composition; using Microsoft.VisualStudio.Composition;
using System.Text;
namespace ICSharpCode.ILSpy namespace ICSharpCode.ILSpy
{ {
@ -233,20 +232,7 @@ namespace ICSharpCode.ILSpy
void Window_RequestNavigate(object sender, RequestNavigateEventArgs e) void Window_RequestNavigate(object sender, RequestNavigateEventArgs e)
{ {
if (e.Uri.Scheme == "resource") { ILSpy.MainWindow.Instance.NavigateTo(e);
AvalonEditTextOutput output = new AvalonEditTextOutput();
using (Stream s = typeof(App).Assembly.GetManifestResourceStream(typeof(App), e.Uri.AbsolutePath)) {
using (StreamReader r = new StreamReader(s)) {
string line;
while ((line = r.ReadLine()) != null) {
output.Write(line);
output.WriteLine();
}
}
}
Docking.DockWorkspace.Instance.ShowText(output);
e.Handled = true;
}
} }
} }
} }

51
ILSpy/MainWindow.xaml.cs

@ -25,7 +25,6 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Reflection.Metadata; using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335; using System.Reflection.Metadata.Ecma335;
using System.Runtime.CompilerServices;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows; using System.Windows;
@ -34,6 +33,7 @@ using System.Windows.Input;
using System.Windows.Interop; using System.Windows.Interop;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Threading; using System.Windows.Threading;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Documentation; using ICSharpCode.Decompiler.Documentation;
@ -41,7 +41,6 @@ using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.TypeSystem.Implementation; using ICSharpCode.Decompiler.TypeSystem.Implementation;
using ICSharpCode.ILSpy.Analyzers; using ICSharpCode.ILSpy.Analyzers;
using ICSharpCode.ILSpy.Controls;
using ICSharpCode.ILSpy.Docking; using ICSharpCode.ILSpy.Docking;
using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.TreeNodes;
@ -49,7 +48,6 @@ using ICSharpCode.ILSpy.ViewModels;
using ICSharpCode.TreeView; using ICSharpCode.TreeView;
using Microsoft.Win32; using Microsoft.Win32;
using OSVersionHelper; using OSVersionHelper;
using Xceed.Wpf.AvalonDock.Layout;
using Xceed.Wpf.AvalonDock.Layout.Serialization; using Xceed.Wpf.AvalonDock.Layout.Serialization;
namespace ICSharpCode.ILSpy namespace ICSharpCode.ILSpy
@ -996,6 +994,10 @@ namespace ICSharpCode.ILSpy
if (node != null && node.View(DockWorkspace.Instance.ActiveTabPage)) if (node != null && node.View(DockWorkspace.Instance.ActiveTabPage))
return; return;
} }
if (newState?.ViewedUri != null) {
NavigateTo(new RequestNavigateEventArgs(newState.ViewedUri, null), recordHistory: false);
return;
}
decompilationTask = DockWorkspace.Instance.ActiveTabPage.ShowTextViewAsync(textView => textView.DecompileAsync(this.CurrentLanguage, this.SelectedNodes, new DecompilationOptions() { TextViewState = newState })); decompilationTask = DockWorkspace.Instance.ActiveTabPage.ShowTextViewAsync(textView => textView.DecompileAsync(this.CurrentLanguage, this.SelectedNodes, new DecompilationOptions() { TextViewState = newState }));
} }
@ -1078,9 +1080,50 @@ namespace ICSharpCode.ILSpy
ignoreDecompilationRequests = false; ignoreDecompilationRequests = false;
DecompileSelectedNodes(newState.ViewState as DecompilerTextViewState, false); DecompileSelectedNodes(newState.ViewState as DecompilerTextViewState, false);
} }
#endregion #endregion
internal void NavigateTo(RequestNavigateEventArgs e, bool recordHistory = true)
{
if (e.Uri.Scheme == "resource") {
if (e.Uri.Host == "aboutpage") {
RecordHistory();
DockWorkspace.Instance.ActiveTabPage.ShowTextView(AboutPage.Display);
e.Handled = true;
return;
}
AvalonEditTextOutput output = new AvalonEditTextOutput {
Address = e.Uri,
Title = e.Uri.AbsolutePath,
EnableHyperlinks = true
};
using (Stream s = typeof(App).Assembly.GetManifestResourceStream(typeof(App), e.Uri.AbsolutePath)) {
using (StreamReader r = new StreamReader(s)) {
string line;
while ((line = r.ReadLine()) != null) {
output.Write(line);
output.WriteLine();
}
}
}
RecordHistory();
DockWorkspace.Instance.ShowText(output);
e.Handled = true;
}
void RecordHistory()
{
if (!recordHistory)
return;
var currentState = DockWorkspace.Instance.ActiveTabPage.GetState();
if (currentState != null)
history.UpdateCurrent(new NavigationState(currentState));
ignoreDecompilationRequests = true;
UnselectAll();
ignoreDecompilationRequests = false;
history.Record(new NavigationState(new ViewState { ViewedUri = e.Uri }));
}
}
protected override void OnStateChanged(EventArgs e) protected override void OnStateChanged(EventArgs e)
{ {
base.OnStateChanged(e); base.OnStateChanged(e);

4
ILSpy/Metadata/Helpers.cs

@ -91,7 +91,9 @@ namespace ICSharpCode.ILSpy.Metadata
public ViewState GetState() public ViewState GetState()
{ {
return new ViewState { DecompiledNodes = SelectedTreeNode == null ? null : new[] { SelectedTreeNode } }; return new ViewState {
DecompiledNodes = SelectedTreeNode == null ? null : new HashSet<ILSpyTreeNode>(new[] { SelectedTreeNode })
};
} }
} }

16
ILSpy/NavigationState.cs

@ -18,11 +18,13 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TextView;
using ICSharpCode.TreeView; using ICSharpCode.TreeView;
namespace ICSharpCode.ILSpy namespace ICSharpCode.ILSpy
{ {
[DebuggerDisplay("Nodes = {treeNodes.Count}, State = [{ViewState}]")]
public class NavigationState : IEquatable<NavigationState> public class NavigationState : IEquatable<NavigationState>
{ {
private readonly HashSet<SharpTreeNode> treeNodes; private readonly HashSet<SharpTreeNode> treeNodes;
@ -32,7 +34,7 @@ namespace ICSharpCode.ILSpy
public NavigationState(ViewState viewState) public NavigationState(ViewState viewState)
{ {
this.treeNodes = new HashSet<SharpTreeNode>(viewState.DecompiledNodes); this.treeNodes = new HashSet<SharpTreeNode>((IEnumerable<SharpTreeNode>)viewState.DecompiledNodes ?? Array.Empty<SharpTreeNode>());
ViewState = viewState; ViewState = viewState;
} }
@ -44,8 +46,16 @@ namespace ICSharpCode.ILSpy
public bool Equals(NavigationState other) public bool Equals(NavigationState other)
{ {
// TODO: should this care about the view state as well? if (!this.treeNodes.SetEquals(other.treeNodes))
return this.treeNodes.SetEquals(other.treeNodes); return false;
if (object.ReferenceEquals(this.ViewState, other.ViewState))
return true;
if (this.ViewState == null)
return false;
return this.ViewState.Equals(other.ViewState);
} }
} }
} }

6
ILSpy/TextView/AvalonEditTextOutput.cs

@ -84,6 +84,12 @@ namespace ICSharpCode.ILSpy.TextView
public string Title { get; set; } public string Title { get; set; }
/// <summary>
/// Gets/sets the <see cref="Uri"/> that is displayed by this view.
/// Used to identify the AboutPage and other views built into ILSpy in the navigation history.
/// </summary>
public Uri Address { get; set; }
internal readonly List<VisualLineElementGenerator> elementGenerators = new List<VisualLineElementGenerator>(); internal readonly List<VisualLineElementGenerator> elementGenerators = new List<VisualLineElementGenerator>();
/// <summary>List of all references that were written to the output</summary> /// <summary>List of all references that were written to the output</summary>

29
ILSpy/TextView/DecompilerTextView.cs

@ -71,6 +71,7 @@ namespace ICSharpCode.ILSpy.TextView
BracketHighlightRenderer bracketHighlightRenderer; BracketHighlightRenderer bracketHighlightRenderer;
FoldingManager foldingManager; FoldingManager foldingManager;
ILSpyTreeNode[] decompiledNodes; ILSpyTreeNode[] decompiledNodes;
Uri currentAddress;
DefinitionLookup definitionLookup; DefinitionLookup definitionLookup;
TextSegmentCollection<ReferenceSegment> references; TextSegmentCollection<ReferenceSegment> references;
@ -647,6 +648,7 @@ namespace ICSharpCode.ILSpy.TextView
if (this.DataContext is PaneModel model) { if (this.DataContext is PaneModel model) {
model.Title = textOutput.Title; model.Title = textOutput.Title;
} }
currentAddress = textOutput.Address;
} }
#endregion #endregion
@ -1010,7 +1012,7 @@ namespace ICSharpCode.ILSpy.TextView
public DecompilerTextViewState GetState() public DecompilerTextViewState GetState()
{ {
if (decompiledNodes == null) if (decompiledNodes == null && currentAddress == null)
return null; return null;
var state = new DecompilerTextViewState(); var state = new DecompilerTextViewState();
@ -1018,7 +1020,8 @@ namespace ICSharpCode.ILSpy.TextView
state.SaveFoldingsState(foldingManager.AllFoldings); state.SaveFoldingsState(foldingManager.AllFoldings);
state.VerticalOffset = textEditor.VerticalOffset; state.VerticalOffset = textEditor.VerticalOffset;
state.HorizontalOffset = textEditor.HorizontalOffset; state.HorizontalOffset = textEditor.HorizontalOffset;
state.DecompiledNodes = decompiledNodes; state.DecompiledNodes = decompiledNodes == null ? null : new HashSet<ILSpyTreeNode>(decompiledNodes);
state.ViewedUri = currentAddress;
return state; return state;
} }
@ -1059,9 +1062,16 @@ namespace ICSharpCode.ILSpy.TextView
#endregion #endregion
} }
public class ViewState [DebuggerDisplay("Nodes = {DecompiledNodes}, ViewedUri = {ViewedUri}")]
public class ViewState : IEquatable<ViewState>
{ {
public ILSpyTreeNode[] DecompiledNodes; public HashSet<ILSpyTreeNode> DecompiledNodes;
public Uri ViewedUri;
public virtual bool Equals(ViewState other)
{
return ViewedUri == other.ViewedUri && (DecompiledNodes == other.DecompiledNodes || DecompiledNodes?.SetEquals(other.DecompiledNodes) == true);
}
} }
public class DecompilerTextViewState : ViewState public class DecompilerTextViewState : ViewState
@ -1084,5 +1094,16 @@ namespace ICSharpCode.ILSpy.TextView
foreach (var folding in list) foreach (var folding in list)
folding.DefaultClosed = !ExpandedFoldings.Any(f => f.Item1 == folding.StartOffset && f.Item2 == folding.EndOffset); folding.DefaultClosed = !ExpandedFoldings.Any(f => f.Item1 == folding.StartOffset && f.Item2 == folding.EndOffset);
} }
public override bool Equals(ViewState other)
{
if (other is DecompilerTextViewState vs) {
return base.Equals(vs)
&& FoldingsChecksum == vs.FoldingsChecksum
&& VerticalOffset == vs.VerticalOffset
&& HorizontalOffset == vs.HorizontalOffset;
}
return false;
}
} }
} }

Loading…
Cancel
Save