Browse Source

Store settings in appdata.

pull/1/head
Daniel Grunwald 15 years ago
parent
commit
0a3bf39aa8
  1. 24
      ILSpy/App.xaml.cs
  2. 21
      ILSpy/FilterSettings.cs
  3. 2
      ILSpy/ILSpy.csproj
  4. 101
      ILSpy/ILSpySettings.cs
  5. 6
      ILSpy/Language.cs
  6. 2
      ILSpy/MainWindow.xaml
  7. 65
      ILSpy/MainWindow.xaml.cs
  8. 73
      ILSpy/SessionSettings.cs

24
ILSpy/App.xaml.cs

@ -18,9 +18,11 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Threading;
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;
namespace ICSharpCode.ILSpy namespace ICSharpCode.ILSpy
{ {
@ -33,11 +35,33 @@ namespace ICSharpCode.ILSpy
{ {
InitializeComponent(); InitializeComponent();
if (!Debugger.IsAttached) {
AppDomain.CurrentDomain.UnhandledException += ShowErrorBox;
Dispatcher.CurrentDispatcher.UnhandledException += Dispatcher_UnhandledException;
}
EventManager.RegisterClassHandler(typeof(Window), EventManager.RegisterClassHandler(typeof(Window),
Hyperlink.RequestNavigateEvent, Hyperlink.RequestNavigateEvent,
new RequestNavigateEventHandler(Window_RequestNavigate)); new RequestNavigateEventHandler(Window_RequestNavigate));
} }
static void Dispatcher_UnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
Debug.WriteLine(e.Exception.ToString());
MessageBox.Show(e.Exception.ToString(), "Sorry, we crashed");
e.Handled = true;
}
static void ShowErrorBox(object sender, UnhandledExceptionEventArgs e)
{
Exception ex = e.ExceptionObject as Exception;
if (ex != null) {
Debug.WriteLine(ex.ToString());
MessageBox.Show(ex.ToString(), "Sorry, we crashed");
}
}
void Window_RequestNavigate(object sender, RequestNavigateEventArgs e) void Window_RequestNavigate(object sender, RequestNavigateEventArgs e)
{ {
Process.Start(e.Uri.ToString()); Process.Start(e.Uri.ToString());

21
ILSpy/FilterSettings.cs

@ -18,6 +18,8 @@
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using System.Linq;
using System.Xml.Linq;
namespace ICSharpCode.ILSpy namespace ICSharpCode.ILSpy
{ {
@ -31,6 +33,21 @@ namespace ICSharpCode.ILSpy
/// </remarks> /// </remarks>
public class FilterSettings : INotifyPropertyChanged public class FilterSettings : INotifyPropertyChanged
{ {
public FilterSettings(XElement element)
{
this.ShowInternalApi = (bool?)element.Element("ShowInternalAPI") ?? true;
this.Language = Languages.GetLanguage((string)element.Element("Language"));
}
public XElement SaveAsXml()
{
return new XElement(
"FilterSettings",
new XElement("ShowInternalAPI", this.ShowInternalApi),
new XElement("Language", this.Language.Name)
);
}
string searchTerm; string searchTerm;
public string SearchTerm { public string SearchTerm {
@ -50,7 +67,7 @@ namespace ICSharpCode.ILSpy
return text.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0; return text.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0;
} }
bool showInternalApi = true; bool showInternalApi;
public bool ShowInternalApi { public bool ShowInternalApi {
get { return showInternalApi; } get { return showInternalApi; }
@ -62,7 +79,7 @@ namespace ICSharpCode.ILSpy
} }
} }
Language language = Languages.AllLanguages[0]; Language language;
public Language Language { public Language Language {
get { return language; } get { return language; }

2
ILSpy/ILSpy.csproj

@ -89,6 +89,7 @@
<Compile Include="Fusion.cs" /> <Compile Include="Fusion.cs" />
<Compile Include="GacInterop.cs" /> <Compile Include="GacInterop.cs" />
<Compile Include="ILLanguage.cs" /> <Compile Include="ILLanguage.cs" />
<Compile Include="ILSpySettings.cs" />
<Compile Include="Language.cs" /> <Compile Include="Language.cs" />
<Compile Include="Images\Images.cs" /> <Compile Include="Images\Images.cs" />
<Compile Include="Mono.Cecil.Rocks\MethodBodyRocks.cs" /> <Compile Include="Mono.Cecil.Rocks\MethodBodyRocks.cs" />
@ -103,6 +104,7 @@
<SubType>Code</SubType> <SubType>Code</SubType>
<DependentUpon>MainWindow.xaml</DependentUpon> <DependentUpon>MainWindow.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="SessionSettings.cs" />
<Compile Include="SortableGridViewColumn.cs" /> <Compile Include="SortableGridViewColumn.cs" />
<Compile Include="TextView\CaretHighlightAdorner.cs" /> <Compile Include="TextView\CaretHighlightAdorner.cs" />
<Compile Include="TextView\DecompilerTextView.cs" /> <Compile Include="TextView\DecompilerTextView.cs" />

101
ILSpy/ILSpySettings.cs

@ -0,0 +1,101 @@
// 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.IO;
using System.Linq;
using System.Threading;
using System.Xml;
using System.Xml.Linq;
namespace ICSharpCode.ILSpy
{
/// <summary>
/// Manages IL Spy settings.
/// </summary>
public static class ILSpySettings
{
public static XElement LoadSettings(string section)
{
using (new MutexProtector(ConfigFileMutex)) {
try {
XDocument doc = XDocument.Load(GetConfigFile());
return doc.Root.Element(section) ?? new XElement(section);
} catch (IOException) {
return new XElement(section);
} catch (XmlException) {
return new XElement(section);
}
}
}
public static void SaveSettings(XElement section)
{
using (new MutexProtector(ConfigFileMutex)) {
string config = GetConfigFile();
XDocument doc;
try {
doc = XDocument.Load(config);
} catch (IOException) {
// ensure the directory exists
Directory.CreateDirectory(Path.GetDirectoryName(config));
doc = new XDocument(new XElement("ILSpy"));
} catch (XmlException) {
doc = new XDocument(new XElement("ILSpy"));
}
doc.Root.SetAttributeValue("version", RevisionClass.Major + "." + RevisionClass.Minor + "." + RevisionClass.Build + "." + RevisionClass.Revision);
XElement existingElement = doc.Root.Element(section.Name);
if (existingElement != null)
existingElement.ReplaceWith(section);
else
doc.Root.Add(section);
doc.Save(config);
}
}
public static string GetConfigFile()
{
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ICSharpCode\\ILSpy.xml");
}
const string ConfigFileMutex = "01A91708-49D1-410D-B8EB-4DE2662B3971";
sealed class MutexProtector : IDisposable
{
Mutex mutex;
public MutexProtector(string name)
{
bool createdNew;
this.mutex = new Mutex(true, name, out createdNew);
if (!createdNew) {
try {
mutex.WaitOne();
} catch (AbandonedMutexException) {
}
}
}
public void Dispose()
{
mutex.ReleaseMutex();
mutex.Dispose();
}
}
}
}

6
ILSpy/Language.cs

@ -18,6 +18,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using Mono.Cecil; using Mono.Cecil;
@ -80,5 +81,10 @@ namespace ICSharpCode.ILSpy
new ILLanguage(false), new ILLanguage(false),
new ILLanguage(true) new ILLanguage(true)
}; };
public static Language GetLanguage(string name)
{
return AllLanguages.FirstOrDefault(l => l.Name == name) ?? AllLanguages.First();
}
} }
} }

2
ILSpy/MainWindow.xaml

@ -3,8 +3,6 @@
x:Class="ICSharpCode.ILSpy.MainWindow" 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" x:Class="ICSharpCode.ILSpy.MainWindow" 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:textView="clr-namespace:ICSharpCode.ILSpy.TextView" xmlns:local="clr-namespace:ICSharpCode.ILSpy" xmlns:textView="clr-namespace:ICSharpCode.ILSpy.TextView"
Title="ILSpy" Title="ILSpy"
Width="790"
Height="500"
MinWidth="250" MinWidth="250"
MinHeight="200" MinHeight="200"
UseLayoutRounding="True" UseLayoutRounding="True"

65
ILSpy/MainWindow.xaml.cs

@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
@ -39,7 +40,7 @@ namespace ICSharpCode.ILSpy
{ {
AssemblyList assemblyList = new AssemblyList(); AssemblyList assemblyList = new AssemblyList();
AssemblyListTreeNode assemblyListTreeNode; AssemblyListTreeNode assemblyListTreeNode;
FilterSettings filterSettings = new FilterSettings(); SessionSettings settings = new SessionSettings();
static readonly System.Reflection.Assembly[] initialAssemblies = { static readonly System.Reflection.Assembly[] initialAssemblies = {
typeof(object).Assembly, typeof(object).Assembly,
@ -58,13 +59,20 @@ namespace ICSharpCode.ILSpy
public MainWindow() public MainWindow()
{ {
this.DataContext = filterSettings; this.DataContext = settings.FilterSettings;
this.Left = settings.WindowBounds.Left;
this.Top = settings.WindowBounds.Top;
this.Width = settings.WindowBounds.Width;
this.Height = settings.WindowBounds.Height;
// TODO: validate bounds (maybe a screen was removed...)
this.WindowState = settings.WindowState;
InitializeComponent(); InitializeComponent();
decompilerTextView.mainWindow = this; decompilerTextView.mainWindow = this;
assemblyListTreeNode = new AssemblyListTreeNode(assemblyList); assemblyListTreeNode = new AssemblyListTreeNode(assemblyList);
assemblyListTreeNode.FilterSettings = filterSettings.Clone(); assemblyListTreeNode.FilterSettings = settings.FilterSettings.Clone();
filterSettings.PropertyChanged += new PropertyChangedEventHandler(filterSettings_PropertyChanged); settings.FilterSettings.PropertyChanged += new PropertyChangedEventHandler(filterSettings_PropertyChanged);
treeView.Root = assemblyListTreeNode; treeView.Root = assemblyListTreeNode;
assemblyListTreeNode.Select = SelectNode; assemblyListTreeNode.Select = SelectNode;
@ -75,6 +83,8 @@ namespace ICSharpCode.ILSpy
assemblyList.OpenAssembly(args[i]); assemblyList.OpenAssembly(args[i]);
} }
SelectNode(FindNodeByPath(settings.ActiveTreeViewPath));
#if DEBUG #if DEBUG
AddDebugItemsToToolbar(); AddDebugItemsToToolbar();
#endif #endif
@ -85,7 +95,7 @@ namespace ICSharpCode.ILSpy
// filterSettings is mutable; but the ILSpyTreeNode filtering assumes that filter settings are immutable. // filterSettings is mutable; but the ILSpyTreeNode filtering assumes that filter settings are immutable.
// Thus, the main window will use one mutable instance (for data-binding), and assign a new clone to the ILSpyTreeNodes whenever the main // Thus, the main window will use one mutable instance (for data-binding), and assign a new clone to the ILSpyTreeNodes whenever the main
// mutable instance changes. // mutable instance changes.
assemblyListTreeNode.FilterSettings = filterSettings.Clone(); assemblyListTreeNode.FilterSettings = settings.FilterSettings.Clone();
if (e.PropertyName == "Language") { if (e.PropertyName == "Language") {
TreeView_SelectionChanged(null, null); TreeView_SelectionChanged(null, null);
} }
@ -103,6 +113,33 @@ namespace ICSharpCode.ILSpy
} }
} }
SharpTreeNode FindNodeByPath(string[] path)
{
if (path == null)
return null;
SharpTreeNode node = treeView.Root;
foreach (var element in path) {
if (node == null)
break;
node.EnsureLazyChildren();
node = node.Children.FirstOrDefault(c => c.ToString() == element);
}
return node;
}
string[] GetPathForNode(SharpTreeNode node)
{
if (node == null)
return null;
List<string> path = new List<string>();
while (node.Parent != null) {
path.Add(node.ToString());
node = node.Parent;
}
path.Reverse();
return path.ToArray();
}
#region Debugging CFG #region Debugging CFG
#if DEBUG #if DEBUG
void AddDebugItemsToToolbar() void AddDebugItemsToToolbar()
@ -213,7 +250,23 @@ namespace ICSharpCode.ILSpy
void TreeView_SelectionChanged(object sender, SelectionChangedEventArgs e) void TreeView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{ {
decompilerTextView.Decompile(filterSettings.Language, treeView.SelectedItems.OfType<ILSpyTreeNodeBase>()); decompilerTextView.Decompile(settings.FilterSettings.Language, treeView.SelectedItems.OfType<ILSpyTreeNodeBase>());
}
protected override void OnStateChanged(EventArgs e)
{
base.OnStateChanged(e);
// store window state in settings only if it's not minimized
if (this.WindowState != System.Windows.WindowState.Minimized)
settings.WindowState = this.WindowState;
}
protected override void OnClosing(CancelEventArgs e)
{
base.OnClosing(e);
settings.ActiveTreeViewPath = GetPathForNode(treeView.SelectedItem as SharpTreeNode);
settings.WindowBounds = this.RestoreBounds;
settings.Save();
} }
} }
} }

73
ILSpy/SessionSettings.cs

@ -0,0 +1,73 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Xml.Linq;
namespace ICSharpCode.ILSpy
{
/// <summary>
/// Per-session setting:
/// Loaded at startup; saved at exit.
/// </summary>
public class SessionSettings
{
public SessionSettings()
{
XElement doc = ILSpySettings.LoadSettings("SessionSettings");
XElement filterSettings = doc.Element("FilterSettings");
if (filterSettings == null) filterSettings = new XElement("FilterSettings");
this.FilterSettings = new FilterSettings(filterSettings);
XElement activeTreeViewPath = doc.Element("ActiveTreeViewPath");
if (activeTreeViewPath != null) {
this.ActiveTreeViewPath = activeTreeViewPath.Elements().Select(e => (string)e).ToArray();
}
this.WindowState = FromString((string)doc.Element("WindowState"), WindowState.Normal);
this.WindowBounds = FromString((string)doc.Element("WindowBounds"), new Rect(10, 10, 750, 550));
}
public FilterSettings FilterSettings;
public string[] ActiveTreeViewPath;
public WindowState WindowState = WindowState.Normal;
public Rect WindowBounds;
public void Save()
{
XElement doc = new XElement("SessionSettings");
doc.Add(this.FilterSettings.SaveAsXml());
if (this.ActiveTreeViewPath != null) {
doc.Add(new XElement("ActiveTreeViewPath", ActiveTreeViewPath.Select(p => new XElement("Node", p))));
}
doc.Add(new XElement("WindowState", ToString(this.WindowState)));
doc.Add(new XElement("WindowBounds", ToString(this.WindowBounds)));
ILSpySettings.SaveSettings(doc);
}
static T FromString<T>(string s, T defaultValue)
{
if (s == null)
return defaultValue;
try {
TypeConverter c = TypeDescriptor.GetConverter(typeof(T));
return (T)c.ConvertFromInvariantString(s);
} catch (FormatException) {
return defaultValue;
}
}
static string ToString<T>(T obj)
{
TypeConverter c = TypeDescriptor.GetConverter(typeof(T));
return c.ConvertToInvariantString(obj);
}
}
}
Loading…
Cancel
Save