diff --git a/App.xaml.cs b/App.xaml.cs index 0aba97692..74b4fc8bb 100644 --- a/App.xaml.cs +++ b/App.xaml.cs @@ -3,6 +3,7 @@ using System.Reflection; using System.Threading; using System.Windows; +using System.Windows.Controls; using System.Windows.Threading; namespace ArIED61850Tester; @@ -19,6 +20,12 @@ protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); + // Keep every IED card on one reusable template key while replacing the + // legacy bitmap fallback with the compact ARVREL-derived vector fascia. + // Installing this before StartupUri materializes also makes the portable + // smoke test validate that the vector ResourceDictionary is packaged. + InstallArvrelMiniIedFascia(); + if (Array.Exists(e.Args, argument => string.Equals(argument, "--portable-smoke-test", StringComparison.OrdinalIgnoreCase))) { @@ -37,6 +44,24 @@ protected override void OnStartup(StartupEventArgs e) new Action(() => _ = AppUpdateCoordinator.RunLazyAsync(_updateCancellation.Token))); } + private void InstallArvrelMiniIedFascia() + { + var fasciaResources = new ResourceDictionary + { + Source = new Uri( + "/ARSAS;component/Resources/ArvrelMiniIedFascia.xaml", + UriKind.Relative) + }; + + if (fasciaResources["ArvrelMiniIedRelayFrontPanelTemplate"] is not ControlTemplate template) + { + throw new InvalidOperationException( + "The packaged ARVREL mini IED fascia resource is missing its ControlTemplate."); + } + + Resources["IedRelayFrontPanelTemplate"] = template; + } + private static int RunPortableSmokeTest() { try diff --git a/Resources/ArvrelMiniIedFascia.xaml b/Resources/ArvrelMiniIedFascia.xaml new file mode 100644 index 000000000..d1642376e --- /dev/null +++ b/Resources/ArvrelMiniIedFascia.xaml @@ -0,0 +1,208 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/ARSAS.Tests/ArvrelMiniIedFasciaTests.cs b/tests/ARSAS.Tests/ArvrelMiniIedFasciaTests.cs new file mode 100644 index 000000000..c5a49ff0d --- /dev/null +++ b/tests/ARSAS.Tests/ArvrelMiniIedFasciaTests.cs @@ -0,0 +1,86 @@ +using System.Xml.Linq; + +namespace ARSAS.Tests; + +public sealed class ArvrelMiniIedFasciaTests +{ + [Fact] + public void CompactArvrelFascia_IsVectorOnlyAndKeepsRecognizableRelayHardware() + { + var document = XDocument.Load(FindRepoFile("Resources/ArvrelMiniIedFascia.xaml")); + XNamespace presentation = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"; + XNamespace x = "http://schemas.microsoft.com/winfx/2006/xaml"; + + var template = document + .Descendants(presentation + "ControlTemplate") + .Single(node => + (string?)node.Attribute(x + "Key") == "ArvrelMiniIedRelayFrontPanelTemplate"); + + var root = template.Elements(presentation + "Grid").Single(); + Assert.Equal("50", (string?)root.Attribute("Width")); + Assert.Equal("50", (string?)root.Attribute("Height")); + + var namedParts = template + .Descendants() + .Select(node => (string?)node.Attribute(x + "Name")) + .Where(name => !string.IsNullOrWhiteSpace(name)) + .Cast() + .ToHashSet(StringComparer.Ordinal); + + Assert.Contains("ArvrelMiniShell", namedParts); + Assert.Contains("ArvrelMiniLedBank", namedParts); + Assert.Contains("ArvrelMiniLcd", namedParts); + Assert.Contains("ArvrelMiniKeypad", namedParts); + Assert.Contains("RelayStateRail", namedParts); + + Assert.Empty(template.Descendants(presentation + "Image")); + Assert.Empty(template.Descendants(presentation + "TextBlock")); + Assert.Contains("{TemplateBinding Foreground}", template.ToString(), StringComparison.Ordinal); + Assert.Contains("#2E6F9E", document.ToString(), StringComparison.OrdinalIgnoreCase); + } + + [Fact] + public void AppStartup_ReplacesLegacyCardTemplateWithPackagedArvrelVector() + { + var source = File.ReadAllText(FindRepoFile("App.xaml.cs")); + + Assert.Contains("InstallArvrelMiniIedFascia();", source, StringComparison.Ordinal); + Assert.Contains( + "/ARSAS;component/Resources/ArvrelMiniIedFascia.xaml", + source, + StringComparison.Ordinal); + Assert.Contains( + "fasciaResources[\"ArvrelMiniIedRelayFrontPanelTemplate\"]", + source, + StringComparison.Ordinal); + Assert.Contains( + "Resources[\"IedRelayFrontPanelTemplate\"] = template;", + source, + StringComparison.Ordinal); + } + + [Fact] + public void ExplorerAndIoFatCards_ContinueToUseOneReusableTemplateKey() + { + var explorer = File.ReadAllText(FindRepoFile("MainWindow.xaml")); + var ioFat = File.ReadAllText(FindRepoFile("IoListTestingWindow.xaml")); + + Assert.Contains("Template=\"{StaticResource IedRelayFrontPanelTemplate}\"", explorer, StringComparison.Ordinal); + Assert.Contains("Template=\"{StaticResource IedRelayFrontPanelTemplate}\"", ioFat, StringComparison.Ordinal); + } + + private static string FindRepoFile(string relativePath) + { + DirectoryInfo? directory = new(AppContext.BaseDirectory); + while (directory != null) + { + var candidate = Path.Combine(directory.FullName, relativePath); + if (File.Exists(candidate)) + return candidate; + directory = directory.Parent; + } + + throw new FileNotFoundException( + $"Could not locate repository file '{relativePath}' from '{AppContext.BaseDirectory}'."); + } +}