PageRenderTime 58ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/App.xaml.cs

https://bitbucket.org/rstarkov/tankiconmaker
C# | 163 lines | 121 code | 19 blank | 23 comment | 14 complexity | 6c671053a9618ae7695a36a9cf9e4700 MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause, GPL-3.0, CC-BY-SA-3.0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.ObjectModel;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Reflection;
  7. using System.Text;
  8. using System.Threading;
  9. using System.Windows;
  10. using RT.Util;
  11. using RT.Util.Dialogs;
  12. using RT.Util.Lingo;
  13. using RT.Util.Serialization;
  14. using WotDataLib;
  15. using WpfCrutches;
  16. using D = System.Drawing;
  17. using W = System.Windows.Media;
  18. namespace TankIconMaker
  19. {
  20. partial class App : Application
  21. {
  22. /// <summary>
  23. /// Various program settings. To ensure that an application crash or a power loss does not result in lost settings,
  24. /// one of the Save methods should be invoked every time changes are made; this is not automatic.
  25. /// </summary>
  26. public static Settings Settings;
  27. /// <summary>Contains the current UI translation.</summary>
  28. public static Translation Translation = new Translation();
  29. /// <summary>
  30. /// Lists all the possible sources of extra properties, sorted and in an observable fashion. This is kept up-to-date
  31. /// by the <see cref="MainWindow"/> and used in data binding by the <see cref="DataSourceEditor"/>.
  32. /// </summary>
  33. public static ObservableSortedList<DataSourceInfo> DataSources = new ObservableSortedList<DataSourceInfo>(
  34. items: new DataSourceInfo[] { new DataSourceTierArabic(), new DataSourceTierRoman() },
  35. comparer: CustomComparer<DataSourceInfo>.By(ds => ds is DataSourceTierArabic ? 0 : ds is DataSourceTierRoman ? 1 : 2)
  36. .ThenBy(ds => ds.Name).ThenBy(ds => ds.Author));
  37. /// <summary>
  38. /// Screen resolution at program start time, relative to the WPF's 96.0 ppi. Windows 7 won't allow this to be changed
  39. /// without a log-off, so it's OK to read this once at start up and assume it doesn't change.
  40. /// </summary>
  41. public static double DpiScaleX, DpiScaleY;
  42. /// <summary>A list of info classes for each layer type defined in this assembly. Initialised once at startup.</summary>
  43. public static IList<TypeInfo<LayerBase>> LayerTypes;
  44. /// <summary>A list of info classes for each effect type defined in this assembly. Initialised once at startup.</summary>
  45. public static IList<TypeInfo<EffectBase>> EffectTypes;
  46. [STAThread]
  47. static int Main(string[] args)
  48. {
  49. // Configure Classify. This goes before the post-build check because it depends on it
  50. Classify.DefaultOptions = new ClassifyOptions()
  51. .AddTypeOptions(typeof(W.Color), new colorTypeOptions())
  52. .AddTypeOptions(typeof(D.Color), new colorTypeOptions())
  53. .AddTypeOptions(typeof(Filename), new filenameTypeOptions())
  54. .AddTypeOptions(typeof(ObservableCollection<LayerBase>), new listLayerBaseOptions())
  55. .AddTypeOptions(typeof(ObservableCollection<EffectBase>), new listEffectBaseOptions());
  56. if (args.Length == 2 && args[0] == "--post-build-check")
  57. return RT.Util.Ut.RunPostBuildChecks(args[1], Assembly.GetExecutingAssembly());
  58. System.Windows.Forms.Application.EnableVisualStyles();
  59. System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false);
  60. #if DEBUG
  61. CompositePath.Tests();
  62. #endif
  63. Thread.CurrentThread.Name = "Main";
  64. #if !DEBUG
  65. AppDomain.CurrentDomain.UnhandledException += (_, ea) =>
  66. {
  67. bool copy = DlgMessage.ShowError(App.Translation.Error.ExceptionGlobal,
  68. App.Translation.Error.ErrorToClipboard_Copy, App.Translation.Error.ErrorToClipboard_OK) == 0;
  69. if (copy)
  70. if (Ut.ClipboardSet(Ut.ExceptionToDebugString(ea.ExceptionObject)))
  71. DlgMessage.ShowInfo(App.Translation.Error.ErrorToClipboard_Copied);
  72. };
  73. #else
  74. var dummy = App.Translation.Error.ExceptionGlobal; // to keep Lingo happy that the string is used
  75. var dummy2 = new StringBuilder(); // to keep the "using" clause used
  76. #endif
  77. // Find all the layer and effect types in the assembly (required before settings are loaded)
  78. App.LayerTypes = findTypes<LayerBase>("layer");
  79. App.EffectTypes = findTypes<EffectBase>("effect");
  80. // Load all settings
  81. SettingsUtil.LoadSettings(out App.Settings);
  82. BackupSettingsIfNecessary();
  83. // Guess the language if the OS language has changed (or this is the first run)
  84. var osLingo = Ut.GetOsLanguage();
  85. if (App.Settings.OsLingo != osLingo)
  86. App.Settings.OsLingo = App.Settings.Lingo = osLingo;
  87. // Load translation
  88. App.Translation = Lingo.LoadTranslationOrDefault<Translation>("TankIconMaker", ref App.Settings.Lingo);
  89. // Run the UI
  90. var app = new App();
  91. app.InitializeComponent();
  92. app.Run();
  93. // Save settings upon exit, even though they should be saved on every change anyway
  94. App.Settings.SaveQuiet();
  95. return 0;
  96. }
  97. private static IList<TypeInfo<T>> findTypes<T>(string name) where T : IHasTypeNameDescription
  98. {
  99. var infos = new List<TypeInfo<T>>();
  100. foreach (var type in Assembly.GetEntryAssembly().GetTypes().Where(t => typeof(T).IsAssignableFrom(t) && !t.IsAbstract))
  101. {
  102. var constructor = type.GetConstructor(new Type[0]);
  103. if (constructor == null)
  104. {
  105. // (the error message will only be seen by maker developers, so it's ok that it's shown before any UI appears)
  106. DlgMessage.ShowWarning("Ignored {1} type \"{0}\" because it does not have a public parameterless constructor.".Fmt(type, name));
  107. }
  108. else
  109. {
  110. infos.Add(new TypeInfo<T>
  111. {
  112. Type = type,
  113. Constructor = () => (T) constructor.Invoke(new object[0]),
  114. Name = type.Name,
  115. Description = type.FullName,
  116. });
  117. }
  118. }
  119. infos.Sort(CustomComparer<TypeInfo<T>>.By(ti => ti.Name));
  120. return infos.AsReadOnly();
  121. }
  122. private static void BackupSettingsIfNecessary()
  123. {
  124. var curVersion = Assembly.GetExecutingAssembly().GetName().Version.Major;
  125. if (App.Settings.SavedByVersion != curVersion)
  126. try
  127. {
  128. var origName = SettingsUtil.GetAttribute<Settings>().GetFileName();
  129. File.Copy(origName, Path.Combine(
  130. Path.GetDirectoryName(origName),
  131. Path.GetFileNameWithoutExtension(origName) + ".v" + App.Settings.SavedByVersion.ToString().PadLeft(3, '0') + Path.GetExtension(origName)));
  132. }
  133. catch { }
  134. App.Settings.SavedByVersion = curVersion;
  135. }
  136. private static void PostBuildCheck(IPostBuildReporter rep)
  137. {
  138. Lingo.PostBuildStep<Translation>(rep, Assembly.GetExecutingAssembly());
  139. Classify.PostBuildStep<Settings>(rep);
  140. Classify.PostBuildStep<Style>(rep);
  141. Classify.PostBuildStep<GameVersionConfig>(rep);
  142. }
  143. }
  144. }