You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

200 lines
6.3 KiB

  1. // Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy of this
  4. // software and associated documentation files (the "Software"), to deal in the Software
  5. // without restriction, including without limitation the rights to use, copy, modify, merge,
  6. // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
  7. // to whom the Software is furnished to do so, subject to the following conditions:
  8. //
  9. // The above copyright notice and this permission notice shall be included in all copies or
  10. // substantial portions of the Software.
  11. //
  12. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  13. // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  14. // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
  15. // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  16. // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  17. // DEALINGS IN THE SOFTWARE.
  18. using System;
  19. using System.Collections.Generic;
  20. using System.ComponentModel;
  21. using System.Globalization;
  22. using System.Linq;
  23. using System.Runtime.CompilerServices;
  24. using System.Text;
  25. using System.Text.RegularExpressions;
  26. using System.Windows;
  27. using System.Xml.Linq;
  28. using ICSharpCode.ILSpy.Docking;
  29. using ICSharpCode.ILSpy.Themes;
  30. using ICSharpCode.ILSpyX.Search;
  31. using ICSharpCode.ILSpyX.Settings;
  32. namespace ICSharpCode.ILSpy
  33. {
  34. /// <summary>
  35. /// Per-session setting:
  36. /// Loaded at startup; saved at exit.
  37. /// </summary>
  38. public sealed class SessionSettings : ISettingsSection
  39. {
  40. public XName SectionName => "SessionSettings";
  41. public void LoadFromXml(XElement section)
  42. {
  43. XElement filterSettings = section.Element("FilterSettings") ?? new XElement("FilterSettings");
  44. LanguageSettings = new(filterSettings, this);
  45. LanguageSettings.PropertyChanged += (sender, e) => PropertyChanged?.Invoke(sender, e);
  46. ActiveAssemblyList = (string)section.Element("ActiveAssemblyList");
  47. ActiveTreeViewPath = section.Element("ActiveTreeViewPath")?.Elements().Select(e => Unescape((string)e)).ToArray();
  48. ActiveAutoLoadedAssembly = (string)section.Element("ActiveAutoLoadedAssembly");
  49. WindowState = FromString((string)section.Element("WindowState"), WindowState.Normal);
  50. WindowBounds = FromString((string)section.Element("WindowBounds"), DefaultWindowBounds);
  51. SelectedSearchMode = FromString((string)section.Element("SelectedSearchMode"), SearchMode.TypeAndMember);
  52. Theme = FromString((string)section.Element(nameof(Theme)), ThemeManager.Current.DefaultTheme);
  53. var culture = (string)section.Element(nameof(CurrentCulture));
  54. CurrentCulture = string.IsNullOrEmpty(culture) ? null : culture;
  55. DockLayout = new(section.Element("DockLayout"));
  56. }
  57. public LanguageSettings LanguageSettings { get; set; }
  58. public SearchMode SelectedSearchMode { get; set; }
  59. private string theme;
  60. public string Theme {
  61. get => theme;
  62. set => SetProperty(ref theme, value);
  63. }
  64. public string[] ActiveTreeViewPath;
  65. public string ActiveAutoLoadedAssembly;
  66. string currentCulture;
  67. public string CurrentCulture {
  68. get { return currentCulture; }
  69. set {
  70. if (currentCulture != value)
  71. {
  72. currentCulture = value;
  73. OnPropertyChanged();
  74. }
  75. }
  76. }
  77. public string ActiveAssemblyList {
  78. get => activeAssemblyList;
  79. set {
  80. if (value != null && value != activeAssemblyList)
  81. {
  82. activeAssemblyList = value;
  83. OnPropertyChanged();
  84. }
  85. }
  86. }
  87. public WindowState WindowState;
  88. public Rect WindowBounds;
  89. internal static Rect DefaultWindowBounds = new(10, 10, 750, 550);
  90. public DockLayoutSettings DockLayout { get; set; }
  91. public XElement SaveToXml()
  92. {
  93. var section = new XElement(SectionName);
  94. section.Add(this.LanguageSettings.SaveAsXml());
  95. if (this.ActiveAssemblyList != null)
  96. {
  97. section.Add(new XElement("ActiveAssemblyList", this.ActiveAssemblyList));
  98. }
  99. if (this.ActiveTreeViewPath != null)
  100. {
  101. section.Add(new XElement("ActiveTreeViewPath", ActiveTreeViewPath.Select(p => new XElement("Node", Escape(p)))));
  102. }
  103. if (this.ActiveAutoLoadedAssembly != null)
  104. {
  105. section.Add(new XElement("ActiveAutoLoadedAssembly", this.ActiveAutoLoadedAssembly));
  106. }
  107. section.Add(new XElement("WindowState", ToString(this.WindowState)));
  108. section.Add(new XElement("WindowBounds", ToString(this.WindowBounds)));
  109. section.Add(new XElement("SelectedSearchMode", ToString(this.SelectedSearchMode)));
  110. section.Add(new XElement(nameof(Theme), ToString(this.Theme)));
  111. if (this.CurrentCulture != null)
  112. {
  113. section.Add(new XElement(nameof(CurrentCulture), this.CurrentCulture));
  114. }
  115. var dockLayoutElement = new XElement("DockLayout");
  116. if (DockLayout.Valid)
  117. {
  118. dockLayoutElement.Add(DockLayout.SaveAsXml());
  119. }
  120. section.Add(dockLayoutElement);
  121. return section;
  122. }
  123. static Regex regex = new("\\\\x(?<num>[0-9A-f]{4})");
  124. private string activeAssemblyList;
  125. static string Escape(string p)
  126. {
  127. StringBuilder sb = new();
  128. foreach (char ch in p)
  129. {
  130. if (char.IsLetterOrDigit(ch))
  131. sb.Append(ch);
  132. else
  133. sb.AppendFormat("\\x{0:X4}", (int)ch);
  134. }
  135. return sb.ToString();
  136. }
  137. static string Unescape(string p)
  138. {
  139. return regex.Replace(p, m => ((char)int.Parse(m.Groups["num"].Value, NumberStyles.HexNumber)).ToString());
  140. }
  141. static T FromString<T>(string s, T defaultValue)
  142. {
  143. if (s == null)
  144. return defaultValue;
  145. try
  146. {
  147. TypeConverter c = TypeDescriptor.GetConverter(typeof(T));
  148. return (T)c.ConvertFromInvariantString(s);
  149. }
  150. catch (FormatException)
  151. {
  152. return defaultValue;
  153. }
  154. }
  155. static string ToString<T>(T obj)
  156. {
  157. TypeConverter c = TypeDescriptor.GetConverter(typeof(T));
  158. return c.ConvertToInvariantString(obj);
  159. }
  160. public event PropertyChangedEventHandler PropertyChanged;
  161. private void OnPropertyChanged([CallerMemberName] string propertyName = null)
  162. {
  163. PropertyChanged?.Invoke(this, new(propertyName));
  164. }
  165. private bool SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
  166. {
  167. if (EqualityComparer<T>.Default.Equals(field, value))
  168. return false;
  169. field = value;
  170. OnPropertyChanged(propertyName);
  171. return true;
  172. }
  173. }
  174. }