-
Notifications
You must be signed in to change notification settings - Fork 0
/
MainWindow.xaml.cs
454 lines (375 loc) · 15.8 KB
/
MainWindow.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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
using Microsoft.Win32;
using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Security.Policy;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace grammlator;
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ActualStatus = new StatusStruct(StatusChanged); // Initial State: no flags are set;
// Initial state:
// ActualStatus.SetFlags(StatusFlags.SourceHasFilename, false);
// ActualStatus.SetFlags(StatusFlags.ResultAvailable, false);
// ActualStatus.SetFlags(StatusFlags.SourceNotEmpty, false);
// ActualStatus.SetFlags(StatusFlags.SourceTextChanged, false);
// ActualStatus.SetFlags(StatusFlags.SourceTextChangedSinceLastTranslate, false);
// new StatusStruct(StatusChanged) calls StatusChanged
// StatusChanged () enables/disables menu items
Title = "grammlator - no file -";
// Set handler to focus one of the textboxes by OnFocusTextbox
FocusTextBox += HandleFocusTextBox;
// and focus the SourceTextbox
OnFocusTextBox(new FocusTextBoxEventArgs(SourceTextBox));
// Set InitialDirectory to avoid the directory containing the assembly as default initial directory
string RecentDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Recent);
SaveSourceOrResultDialog.InitialDirectory = RecentDirectory;
OpenSourceFileDialog.InitialDirectory = RecentDirectory;
MainUserInterfaceMethods.SetExampleMenus(MenuItemDisplayExample, this, "GrammlatorExamples.zip");
}
const String fileFilter = "cs files (*.cs)|*.cs|All files (*.*)|*.*";
readonly OpenFileDialog OpenSourceFileDialog = new()
{
AddExtension = false,
ReadOnlyChecked = true,
FilterIndex = 2,
Filter = fileFilter
};
readonly SaveFileDialog SaveSourceOrResultDialog = new()
{
AddExtension = false,
FilterIndex = 2,
Filter = fileFilter
};
private void MenuItemSaveSource_Click(Object sender, RoutedEventArgs e)
{
SaveSource();
}
private void MenuItemLoadSourceFile_Click(Object sender, RoutedEventArgs e)
{
if (!AllowReplaceSourceBoxTextIfChanged(StatusFlags.SourceTextChanged, "The source textbox has been edited and not yet saved!"))
return;
LoadSourcefile();
}
private void MenuItemClearSourceTextbox_Click(Object sender, RoutedEventArgs e)
{
if (!AllowReplaceSourceBoxTextIfChanged(StatusFlags.SourceTextChanged, "The source textbox has been edited and not yet saved!"))
return;
SourceTextBox.Clear();
SourceFilename = "";
ActualStatus.SetFlags(
StatusFlags.SourceHasFilename | StatusFlags.SourceNotEmpty
| StatusFlags.SourceTextChanged | StatusFlags.SourceTextChangedSinceLastTranslate
, false);
ClearAllResultsAndErrorBoxes();
}
private void SaveSource()
{
if (!SaveFile(SourceFilename, "Save source file", SourceTextBox.Text, true))
return;
// Source has been saved (may be with a different filename)
// TODO mark sourcefile as unchanged (has been saved)
SourceFilename = SaveSourceOrResultDialog.FileName;
ActualStatus.SetFlags(StatusFlags.SourceHasFilename, true);
ActualStatus.SetFlags(
StatusFlags.SourceTextChanged | StatusFlags.SourceTextChangedSinceLastTranslate,
false);
}
private void MenuItemSaveResult_Click(Object sender, RoutedEventArgs e)
{
if (!ActualStatus.TestFlags(StatusFlags.ResultAvailable))
{
// this should not occur because the "SaveResult" should be disabled
MessageBox.Show("No result available");
return;
};
// Preset ResultFilename with SourceFilename+"-generated"
String ResultFilename = "";
if (SourceFilename != "")
ResultFilename =
Path.GetDirectoryName(SourceFilename) + "\\" +
Path.GetFileNameWithoutExtension(SourceFilename) + "-generated" +
Path.GetExtension(SourceFilename);
// SaveFile will display warnings if saving to source
if (!SaveFile(ResultFilename, "Save result", ResultTextBox.Text, false))
return;
// Result has been saved
}
private bool SaveFile(string lastFileName, string title, string text, bool saveOfSource)
{
Debug.Assert(!String.IsNullOrEmpty(title));
if (lastFileName != "")
{
SaveSourceOrResultDialog.InitialDirectory = Path.GetDirectoryName(lastFileName);
SaveSourceOrResultDialog.FileName = Path.GetFileName(lastFileName);
}
SaveSourceOrResultDialog.Title = title;
/*** Show SaveFileDialog ***/
Boolean? r = SaveSourceOrResultDialog.ShowDialog();
if (r != true)
return false; // canceled by user
// Did the user select the source file?
bool SourceFileReplace = SourceFilename != "" && SourceFilename == SaveSourceOrResultDialog.FileName;
if (!saveOfSource && SourceFileReplace)
{
// ask user if source textbox content and source file should be replaced by result
// a) least problem: no change of textbox since last load
if (!ActualStatus.TestFlags(StatusFlags.SourceTextChanged))
{
if (MessageBoxResult.Cancel == MessageBox.Show("Copy the result to the source text and save to source file? (source has not been edited)",
"Save result to source?", MessageBoxButton.OKCancel)
)
return false;
}
// b) minor problem: no change of textbox since last translate (will be included in the result)
else if (!ActualStatus.TestFlags(StatusFlags.SourceTextChangedSinceLastTranslate))
{
if (MessageBoxResult.Cancel == MessageBox.Show("Copy the result to the source text and save it to the source file? (source has been edited and then translated)",
"Save result to source?", MessageBoxButton.OKCancel)
)
return false;
}
// c) be careful: change of textbox since last successful translate (will be lost)
else
{
if (MessageBoxResult.Cancel == MessageBox.Show("Copy the result to the source text and save to source file? (source has been edited since last successful translation !)",
"Save result to source?", MessageBoxButton.OKCancel)
)
return false;
}
// "Replacing the source file with the result of the last translation will also replace the contents of the source textbox. The textbox has been edited since the last successfull translation!"
if (MessageBoxResult.Cancel == MessageBox.Show("Copy the result to the source file and then to the source text?",
"Save result to source?", MessageBoxButton.OKCancel)
)
return false;
// Copy result to source to stay consistent
SourceTextBox.Text = ResultTextBox.Text;
}
try
{
File.WriteAllText(SaveSourceOrResultDialog.FileName, text);
}
catch (Exception ex)
{
MessageBox.Show($"Error: Could not write to file. Original error: {ex.Message}");
return false;
}
if (SourceFileReplace)
{
SourceFilename = SaveSourceOrResultDialog.FileName;
ActualStatus.SetFlags(StatusFlags.SourceHasFilename, true);
ActualStatus.SetFlags(
StatusFlags.SourceTextChanged | StatusFlags.SourceTextChangedSinceLastTranslate,
false); // has just been saved
}
return true;
}
private void MenuItemSaveResultToSource_Click(Object sender, RoutedEventArgs e)
{
if (!ActualStatus.TestFlags(StatusFlags.ResultAvailable))
{
// this should not occur because the "SaveResultToSource" should be disabled
MessageBox.Show("No result available");
return;
}
if (!AllowReplaceSourceBoxTextIfChanged(StatusFlags.SourceTextChangedSinceLastTranslate,
"The source textbox has been edited since last successful translation and not yet saved!")
)
return;
SourceTextBox.Text = ResultTextBox.Text;
SaveSource();
}
private void MenuItemTranslateStandard_Click(Object _1, RoutedEventArgs _2)
=> Translate();
private void MenuItemReloadAndTranslate_Click(Object sender, RoutedEventArgs e)
{
if (String.IsNullOrEmpty(SourceFilename))
{
MessageBox.Show("unknown filename");
return;
}
if (!AllowReplaceSourceBoxTextIfChanged(StatusFlags.SourceTextChanged, "The source textbox has been edited and not yet saved!"))
return;
if (ClearResultsAndReadFileToSourceTextbox(SourceFilename))
Translate();
}
private Boolean LoadSourcefile()
{
OpenSourceFileDialog.FileName = "";
if (!String.IsNullOrEmpty(SourceFilename))
{
OpenSourceFileDialog.InitialDirectory = Path.GetDirectoryName(SourceFilename);
OpenSourceFileDialog.FileName = Path.GetFileName(SourceFilename);
}
OpenSourceFileDialog.Title = "Load source file";
Boolean? result = OpenSourceFileDialog.ShowDialog();
if (result != true)
return false; // canceled by user
return ClearResultsAndReadFileToSourceTextbox(OpenSourceFileDialog.FileName); // and set ActualStatus
}
private void CompareIgnoringSeparators_Click(Object _1, RoutedEventArgs _2)
{
/* Compare result and source
* and set both cursors to the first lines which are different.
* Thereby ignore text after #region and after #endregion up to the end of the line
* because this may contain the time of the grammlator translation which is not relevant
*/
CompareSourceAndResultSpan(SourceTextBox.Text, ResultTextBox.Text,
out ReadOnlySpan<Char> differingSourceLine, out ReadOnlySpan<Char> differingResultLine,
out Int32 sourceDiffIndex, out Int32 resultDiffIndex);
SetCursorTo(0, SourceTextBox, sourceDiffIndex, differingSourceLine.Length < 3 ? 3 : differingSourceLine.Length);
SetCursorTo(6, ResultTextBox, resultDiffIndex, differingResultLine.Length < 3 ? 3 : differingResultLine.Length);
GrammlatorTabControl.SelectedIndex = 0;
OnFocusTextBox(new FocusTextBoxEventArgs(SourceTextBox));
}
internal void MenuItemDisplayExample_Click(Object sender, RoutedEventArgs e)
{
if (sender is MenuItem menuItem
&& menuItem.HasHeader
&& menuItem.Header is String header)
{
// use header as name of zip-file element
MainUserInterfaceMethods
.CopyExampleToInfoTextBox(header, InfoTextBox);
GrammlatorTabControl.SelectedIndex = 7;
OnFocusTextBox(new FocusTextBoxEventArgs(InfoTextBox));
return;
}
// error !!!
return;
}
private void DisplaySettings_Click(Object sender, RoutedEventArgs e)
{
StringBuilder InfoBuilder = new(1000);
String Delimiter;
InfoBuilder.AppendLine("The grammlator settings are:").AppendLine();
foreach (Setting s in GlobalSettings.VisibleSettings)
{
if (s.HasType == Setting.SettingType.StringType)
Delimiter = "\"";
else
Delimiter = "";
InfoBuilder.Append(s.Name).Append(": ")
.Append(Delimiter).Append(s.InitialValueAsString).Append(Delimiter)
.AppendLine(";")
.Append("/* ").Append(s.Description).AppendLine(" */")
.AppendLine();
}
InfoTextBox.Text = InfoBuilder.ToString();
GrammlatorTabControl.SelectedIndex = 7;
OnFocusTextBox(new FocusTextBoxEventArgs(InfoTextBox));
}
private readonly StringBuilder InfoBuilder = new(1000);
private void MenuItemDisplaySettingsCompact_Click(Object sender, RoutedEventArgs e)
{
String Delimiter;
InfoBuilder
.Clear()
.AppendLine("The grammlator settings are:")
.AppendLine();
foreach (Setting s in GlobalSettings.VisibleSettings)
{
if (s.HasType == Setting.SettingType.StringType)
Delimiter = "\"";
else
Delimiter = "";
InfoBuilder
.Append("//| ")
.Append(s.Name).Append(": ")
.Append(Delimiter).Append(s.InitialValueAsString).Append(Delimiter)
.AppendLine(";");
}
InfoTextBox.Text = InfoBuilder.ToString();
GrammlatorTabControl.SelectedIndex = 7;
OnFocusTextBox(new FocusTextBoxEventArgs(InfoTextBox));
}
private void MenuItemDisplayVersion_Click(Object sender, RoutedEventArgs e)
{
InfoBuilder
.Clear()
.AppendLine("Grammlator version info:")
.AppendLine()
.AppendLine(GlobalVariables.GetVersioninfo);
InfoTextBox.Text = InfoBuilder.ToString();
GrammlatorTabControl.SelectedIndex = 7;
OnFocusTextBox(new FocusTextBoxEventArgs(InfoTextBox));
}
private void SourceTextBox_TextChanged(object sender, TextChangedEventArgs args)
{
ActualStatus.SetFlags(
StatusFlags.SourceTextChanged | StatusFlags.SourceTextChangedSinceLastTranslate, true
);
TextBox tb = (TextBox)sender;
ActualStatus.SetFlags(StatusFlags.SourceNotEmpty, tb.LineCount >= 5);
}
private void SourceTextBox_MouseEnter(Object sender, System.Windows.Input.MouseEventArgs e)
{
SourceTextBox.Focus();
}
private void ResultTextBox_MouseEnter(Object sender, System.Windows.Input.MouseEventArgs e)
{
ResultTextBox.Focus();
}
public class FocusTextBoxEventArgs : EventArgs
{
public FocusTextBoxEventArgs(TextBox? box)
{
Box = box;
}
internal TextBox? Box { get; set; }
}
public event EventHandler<FocusTextBoxEventArgs> FocusTextBox;
/// <summary>
/// While handling a double click on an error TextBox a call of
/// SourceTextBox.Focus() has no effect.
/// This problem is solved by <see cref="OnFocusTextBox(FocusTextBoxEventArgs)"/>,
/// which raises an event. This event is handled by the MainWindow.
/// </summary>
/// <param name="e">typically the source textbox</param>
protected virtual void OnFocusTextBox(FocusTextBoxEventArgs e)
{
FocusTextBox?.Invoke(this, e); // invokes HandleFocusTextBox
}
void HandleFocusTextBox(object? sender, FocusTextBoxEventArgs e)
{
e.Box?.Focus();
}
private void ErrorBox_DoubleClick(Object sender, RoutedEventArgs e)
{
OnFocusTextBox(new FocusTextBoxEventArgs(SourceTextBox));
}
private void ErrorBox_GotFocus(Object sender, RoutedEventArgs e)
{
// Set cursor of the source textbox
if (sender is TextBox tb)
{
// The name of the error textbox contains its number, which is used to index ErrorPositions
Int32 Index = Int32.Parse(tb.Name.AsSpan(1), NumberStyles.Integer, CultureInfo.InvariantCulture);
if (Index < ErrorPositions.Count)
SetCursorOfSourceTextbox(ErrorPositions[Index]);
}
}
private void ListBox_SizeChanged(Object sender, SizeChangedEventArgs _)
{ // Adjust Width of contained TextBox (may be contained in a ListBoxItem)
if (sender is not ListBox lb)
return;
foreach (Object? o in lb.Items)
if (o is TextBox tb)
tb.Width = lb.ActualWidth - ListboxDistanceAtRight; // try to avoid horizontal scrollbar in Listbox
else if (o is ListBoxItem li && li.Content is TextBox containedTb)
{
// li.Width is OK !
containedTb.Width = li.ActualWidth - ListboxDistanceAtRight;
}
}
}