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.

237 lines
7.5 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.Composition;
  21. using System.IO;
  22. using System.Text.RegularExpressions;
  23. using System.Windows;
  24. using System.Windows.Controls;
  25. using System.Windows.Controls.Primitives;
  26. using System.Windows.Data;
  27. using System.Windows.Input;
  28. using System.Windows.Navigation;
  29. using ICSharpCode.AvalonEdit.Rendering;
  30. using ICSharpCode.Decompiler;
  31. using ICSharpCode.ILSpy.Properties;
  32. using ICSharpCode.ILSpy.TextView;
  33. using ICSharpCode.ILSpy.Themes;
  34. using ICSharpCode.ILSpy.Updates;
  35. using ICSharpCode.ILSpy.ViewModels;
  36. namespace ICSharpCode.ILSpy
  37. {
  38. [ExportMainMenuCommand(ParentMenuID = nameof(Resources._Help), Header = nameof(Resources._About), MenuOrder = 99999)]
  39. [Shared]
  40. public sealed class AboutPage : SimpleCommand
  41. {
  42. readonly SettingsService settingsService;
  43. readonly IEnumerable<IAboutPageAddition> aboutPageAdditions;
  44. public AboutPage(SettingsService settingsService, IEnumerable<IAboutPageAddition> aboutPageAdditions)
  45. {
  46. this.settingsService = settingsService;
  47. this.aboutPageAdditions = aboutPageAdditions;
  48. MessageBus<ShowAboutPageEventArgs>.Subscribers += (_, e) => ShowAboutPage(e.TabPage);
  49. }
  50. public override void Execute(object parameter)
  51. {
  52. MessageBus.Send(this, new NavigateToEventArgs(new RequestNavigateEventArgs(new Uri("resource://aboutpage"), null), inNewTabPage: true));
  53. }
  54. private void ShowAboutPage(TabPageModel tabPage)
  55. {
  56. tabPage.ShowTextView(Display);
  57. }
  58. private void Display(DecompilerTextView textView)
  59. {
  60. AvalonEditTextOutput output = new AvalonEditTextOutput() {
  61. Title = Resources.About,
  62. EnableHyperlinks = true
  63. };
  64. output.WriteLine(Resources.ILSpyVersion + DecompilerVersionInfo.FullVersionWithCommitHash);
  65. string prodVersion = GetDotnetProductVersion();
  66. output.WriteLine(Resources.NETFrameworkVersion + prodVersion);
  67. output.AddUIElement(
  68. delegate {
  69. var stackPanel = new StackPanel {
  70. HorizontalAlignment = HorizontalAlignment.Center,
  71. Orientation = Orientation.Horizontal
  72. };
  73. if (UpdateService.LatestAvailableVersion == null)
  74. {
  75. AddUpdateCheckButton(stackPanel, textView);
  76. }
  77. else
  78. {
  79. // we already retrieved the latest version sometime earlier
  80. ShowAvailableVersion(UpdateService.LatestAvailableVersion, stackPanel);
  81. }
  82. var checkBox = new CheckBox {
  83. Margin = new Thickness(4),
  84. Content = Resources.AutomaticallyCheckUpdatesEveryWeek
  85. };
  86. var settings = settingsService.GetSettings<UpdateSettings>();
  87. checkBox.SetBinding(ToggleButton.IsCheckedProperty, new Binding("AutomaticUpdateCheckEnabled") { Source = settings });
  88. return new StackPanel {
  89. Margin = new Thickness(0, 4, 0, 0),
  90. Cursor = Cursors.Arrow,
  91. Children = { stackPanel, checkBox }
  92. };
  93. });
  94. output.WriteLine();
  95. foreach (var plugin in aboutPageAdditions)
  96. plugin.Write(output);
  97. output.WriteLine();
  98. output.Address = new Uri("resource://AboutPage");
  99. using (Stream s = typeof(AboutPage).Assembly.GetManifestResourceStream(typeof(AboutPage), Resources.ILSpyAboutPageTxt))
  100. {
  101. using (StreamReader r = new StreamReader(s))
  102. {
  103. while (r.ReadLine() is { } line)
  104. {
  105. output.WriteLine(line);
  106. }
  107. }
  108. }
  109. output.AddVisualLineElementGenerator(new MyLinkElementGenerator("MIT License", "resource:license.txt"));
  110. output.AddVisualLineElementGenerator(new MyLinkElementGenerator("third-party notices", "resource:third-party-notices.txt"));
  111. textView.ShowText(output);
  112. }
  113. private static string GetDotnetProductVersion()
  114. {
  115. // In case of AOT .Location is null, we need a fallback for that
  116. string assemblyLocation = typeof(Uri).Assembly.Location;
  117. if (!String.IsNullOrWhiteSpace(assemblyLocation))
  118. {
  119. return System.Diagnostics.FileVersionInfo.GetVersionInfo(assemblyLocation).ProductVersion;
  120. }
  121. else
  122. {
  123. var version = typeof(Object).Assembly.GetName().Version;
  124. if (version != null)
  125. {
  126. return version.ToString();
  127. }
  128. }
  129. return "UNKNOWN";
  130. }
  131. sealed class MyLinkElementGenerator : LinkElementGenerator
  132. {
  133. readonly Uri uri;
  134. public MyLinkElementGenerator(string matchText, string url) : base(new Regex(Regex.Escape(matchText)))
  135. {
  136. this.uri = new Uri(url);
  137. this.RequireControlModifierForClick = false;
  138. }
  139. protected override Uri GetUriFromMatch(Match match)
  140. {
  141. return uri;
  142. }
  143. }
  144. static void AddUpdateCheckButton(StackPanel stackPanel, DecompilerTextView textView)
  145. {
  146. Button button = ThemeManager.Current.CreateButton();
  147. button.Content = Resources.CheckUpdates;
  148. button.Cursor = Cursors.Arrow;
  149. stackPanel.Children.Add(button);
  150. button.Click += async delegate {
  151. button.Content = Resources.Checking;
  152. button.IsEnabled = false;
  153. try
  154. {
  155. AvailableVersionInfo vInfo = await UpdateService.GetLatestVersionAsync();
  156. stackPanel.Children.Clear();
  157. ShowAvailableVersion(vInfo, stackPanel);
  158. }
  159. catch (Exception ex)
  160. {
  161. AvalonEditTextOutput exceptionOutput = new AvalonEditTextOutput();
  162. exceptionOutput.WriteLine(ex.ToString());
  163. textView.ShowText(exceptionOutput);
  164. }
  165. };
  166. }
  167. static void ShowAvailableVersion(AvailableVersionInfo availableVersion, StackPanel stackPanel)
  168. {
  169. if (AppUpdateService.CurrentVersion == availableVersion.Version)
  170. {
  171. stackPanel.Children.Add(
  172. new Image {
  173. Width = 16, Height = 16,
  174. Source = Images.OK,
  175. Margin = new Thickness(4, 0, 4, 0)
  176. });
  177. stackPanel.Children.Add(
  178. new TextBlock {
  179. Text = Resources.UsingLatestRelease,
  180. VerticalAlignment = VerticalAlignment.Bottom
  181. });
  182. }
  183. else if (AppUpdateService.CurrentVersion < availableVersion.Version)
  184. {
  185. stackPanel.Children.Add(
  186. new TextBlock {
  187. Text = string.Format(Resources.VersionAvailable, availableVersion.Version),
  188. Margin = new Thickness(0, 0, 8, 0),
  189. VerticalAlignment = VerticalAlignment.Bottom
  190. });
  191. if (availableVersion.DownloadUrl != null)
  192. {
  193. Button button = ThemeManager.Current.CreateButton();
  194. button.Content = Resources.Download;
  195. button.Cursor = Cursors.Arrow;
  196. button.Click += delegate {
  197. GlobalUtils.OpenLink(availableVersion.DownloadUrl);
  198. };
  199. stackPanel.Children.Add(button);
  200. }
  201. }
  202. else
  203. {
  204. stackPanel.Children.Add(new TextBlock { Text = Resources.UsingNightlyBuildNewerThanLatestRelease });
  205. }
  206. }
  207. }
  208. /// <summary>
  209. /// Interface that allows plugins to extend the about page.
  210. /// </summary>
  211. public interface IAboutPageAddition
  212. {
  213. void Write(ISmartTextOutput textOutput);
  214. }
  215. }