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