diff --git a/Leibit.BLL/InitializationBLL.cs b/Leibit.BLL/InitializationBLL.cs index 12ff8a27..21978b34 100644 --- a/Leibit.BLL/InitializationBLL.cs +++ b/Leibit.BLL/InitializationBLL.cs @@ -266,6 +266,7 @@ private ESTW __GetEstw(XmlNode node, Area area) var EstwDataFile = node.Attributes["dataFile"]; var InfrastructureManagerAttr = node.Attributes["infrastructureManager"]; var IgnoreRoutingDigitsAttr = node.Attributes["ignoreRoutingDigits"]; + var ProductNameAttr = node.Attributes["productName"]; if (EstwId == null || EstwName == null || EstwDataFile == null || InfrastructureManagerAttr == null || !Enum.TryParse(InfrastructureManagerAttr.InnerText, true, out eInfrastructureManager InfrastructureManager)) return null; @@ -275,7 +276,7 @@ private ESTW __GetEstw(XmlNode node, Area area) if (IgnoreRoutingDigitsAttr != null && !bool.TryParse(IgnoreRoutingDigitsAttr.InnerText, out IgnoreRoutingDigits)) return null; - return new ESTW(EstwId.InnerText, EstwName.InnerText, EstwDataFile.InnerText, InfrastructureManager, IgnoreRoutingDigits, area); + return new ESTW(EstwId.InnerText, EstwName.InnerText, EstwDataFile.InnerText, InfrastructureManager, IgnoreRoutingDigits, ProductNameAttr?.InnerText ?? EstwName.InnerText, area); } #endregion diff --git a/Leibit.BLL/Leibit.BLL.csproj b/Leibit.BLL/Leibit.BLL.csproj index 3f46faa0..fbc79ecc 100644 --- a/Leibit.BLL/Leibit.BLL.csproj +++ b/Leibit.BLL/Leibit.BLL.csproj @@ -17,6 +17,7 @@ pdbonly + diff --git a/Leibit.BLL/SettingsBLL.cs b/Leibit.BLL/SettingsBLL.cs index 086fda82..61b688a3 100644 --- a/Leibit.BLL/SettingsBLL.cs +++ b/Leibit.BLL/SettingsBLL.cs @@ -21,7 +21,8 @@ public class SettingsBLL : BLLBase #region - Ctor - public SettingsBLL() { - m_SettingsFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "LeiBIT", "settings.json"); + __MoveSettingsFileIfNeeded(); + m_SettingsFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "LeibitForESTWsim", "settings.json"); } #endregion @@ -257,6 +258,21 @@ private Settings __GetDefaultSettings() return settings; } + private void __MoveSettingsFileIfNeeded() + { + var oldFileDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "LeiBIT"); + var oldFilePath = Path.Combine(oldFileDirectory, "settings.json"); + var newFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "LeibitForESTWsim", "settings.json"); + + if (File.Exists(oldFilePath) && !File.Exists(newFilePath)) + File.Move(oldFilePath, newFilePath); + else if (File.Exists(oldFilePath) && File.Exists(newFilePath)) + File.Delete(oldFilePath); + + if (Directory.Exists(oldFileDirectory) && !Directory.EnumerateFiles(oldFileDirectory).Any()) + Directory.Delete(oldFileDirectory); + } + #endregion } diff --git a/Leibit.BLL/SoftwareInfoBLL.cs b/Leibit.BLL/SoftwareInfoBLL.cs new file mode 100644 index 00000000..37dd3932 --- /dev/null +++ b/Leibit.BLL/SoftwareInfoBLL.cs @@ -0,0 +1,75 @@ +using Leibit.Core.Common; +using Leibit.Entities; +using Microsoft.Win32; +using System; +using System.Runtime.InteropServices; + +namespace Leibit.BLL +{ + public class SoftwareInfoBLL : BLLBase + { + + #region - Public methods - + + #region [GetSoftwareInfo] + public OperationResult GetSoftwareInfo(string softwareName) + { + try + { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + return OperationResult.Ok(new SoftwareInfo { IsInstalled = false }); + + var key = __Search(Registry.CurrentUser, softwareName); + + if (key == null) + key = __Search(Registry.LocalMachine, softwareName); + + if (key == null) + return OperationResult.Ok(new SoftwareInfo { IsInstalled = false }); + + var result = new SoftwareInfo(); + result.IsInstalled = true; + result.DisplayName = key.GetValue("DisplayName")?.ToString(); + result.DisplayVersion = key.GetValue("DisplayVersion")?.ToString(); + result.InstallLocation = key.GetValue("InstallLocation")?.ToString(); + return OperationResult.Ok(result); + } + catch (Exception ex) + { + return OperationResult.Fail(ex.ToString()); + } + } + #endregion + + #endregion + + #region - Private helpers - + + #region [__Search] + private RegistryKey __Search(RegistryKey key, string softwareName) + { + var baseKey = key.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"); + + foreach (var subKeyName in baseKey.GetSubKeyNames()) + { + var candidate = baseKey.OpenSubKey(subKeyName); + var displayName = candidate.GetValue("DisplayName")?.ToString(); + + if (displayName == null) + continue; + + displayName = displayName.Replace(" ", string.Empty).Replace("-", string.Empty); + softwareName = softwareName.Replace(" ", string.Empty).Replace("-", string.Empty); + + if (displayName.Contains(softwareName)) + return candidate; + } + + return null; + } + #endregion + + #endregion + + } +} diff --git a/Leibit.Client.WPF/Leibit.Client.WPF.csproj b/Leibit.Client.WPF/Leibit.Client.WPF.csproj index 7706f871..bd0f42f2 100644 --- a/Leibit.Client.WPF/Leibit.Client.WPF.csproj +++ b/Leibit.Client.WPF/Leibit.Client.WPF.csproj @@ -1,8 +1,8 @@ - + WinExe LeiBIT - netcoreapp3.1 + net6.0-windows10.0.17763.0 {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} true SAK @@ -18,19 +18,22 @@ full + 1701;1702;WFAC010 pdbonly + 1701;1702;WFAC010 icon.ico - 0.5.5 + 0.6.0 https://github.com/jannikbecker/leibit https://github.com/jannikbecker/leibit app.manifest + @@ -75,6 +78,7 @@ + diff --git a/Leibit.Client.WPF/Resources/Images/bildfpl.png b/Leibit.Client.WPF/Resources/Images/bildfpl.png new file mode 100644 index 00000000..069b2500 Binary files /dev/null and b/Leibit.Client.WPF/Resources/Images/bildfpl.png differ diff --git a/Leibit.Client.WPF/Resources/ResourceDictionary.xaml b/Leibit.Client.WPF/Resources/ResourceDictionary.xaml index 6b712f57..a604da40 100644 --- a/Leibit.Client.WPF/Resources/ResourceDictionary.xaml +++ b/Leibit.Client.WPF/Resources/ResourceDictionary.xaml @@ -1,6 +1,7 @@  + diff --git a/Leibit.Client.WPF/ViewModels/MainViewModel.cs b/Leibit.Client.WPF/ViewModels/MainViewModel.cs index e60eeaad..5e614ca7 100644 --- a/Leibit.Client.WPF/ViewModels/MainViewModel.cs +++ b/Leibit.Client.WPF/ViewModels/MainViewModel.cs @@ -58,6 +58,7 @@ public class MainViewModel : WindowViewModelBase private readonly LiveDataBLL m_LiveDataBll; private readonly SettingsBLL m_SettingsBll; private readonly SerializationBLL m_SerializationBll; + private readonly SoftwareInfoBLL m_SoftwareInfoBll; private UpdateBLL m_UpdateBll; private Area m_CurrentArea; @@ -65,6 +66,7 @@ public class MainViewModel : WindowViewModelBase private CancellationTokenSource m_CancellationTokenSource; private string m_CurrentFilename; private bool m_ForceClose; + private SoftwareInfo m_BildFplInfo; private CommandHandler m_NewCommand; private CommandHandler m_OpenCommand; @@ -72,6 +74,7 @@ public class MainViewModel : WindowViewModelBase private CommandHandler m_SaveAsCommand; private CommandHandler m_SettingsCommand; private CommandHandler m_EstwOnlineCommand; + private CommandHandler m_BildFplCommand; private CommandHandler m_ExitCommand; private CommandHandler m_EstwSelectionCommand; private CommandHandler m_TrainProgressInformationCommand; @@ -98,12 +101,29 @@ public class MainViewModel : WindowViewModelBase #region - Ctor - public MainViewModel() { + m_InitializationBll = new InitializationBLL(); + m_LiveDataBll = new LiveDataBLL(); + m_SettingsBll = new SettingsBLL(); + m_SerializationBll = new SerializationBLL(); + m_SoftwareInfoBll = new SoftwareInfoBLL(); + + var BildFplResult = m_SoftwareInfoBll.GetSoftwareInfo("Bildfahrplan"); + + if (BildFplResult.Succeeded) + m_BildFplInfo = BildFplResult.Result; + else + { + ShowMessage(BildFplResult); + m_BildFplInfo = new SoftwareInfo { IsInstalled = false }; + } + m_NewCommand = new CommandHandler(__New, true); m_OpenCommand = new CommandHandler(__Open, true); m_SaveCommand = new CommandHandler(__Save, false); m_SaveAsCommand = new CommandHandler(__SaveAs, false); m_SettingsCommand = new CommandHandler(__Settings, true); m_EstwOnlineCommand = new CommandHandler(__StartEstwOnline, true); + m_BildFplCommand = new CommandHandler(__StartBildFpl, IsBildFplInstalled); m_ExitCommand = new CommandHandler(__Exit, true); m_EstwSelectionCommand = new CommandHandler(__ShowEstwSelectionWindow, false); m_TrainProgressInformationCommand = new CommandHandler(__ShowTrainProgressInformationWindow, false); @@ -118,11 +138,6 @@ public MainViewModel() m_AboutCommand = new CommandHandler(__ShowAboutWindow, true); m_DebugModeCommand = new CommandHandler(__ToggleDebugMode, true); - m_InitializationBll = new InitializationBLL(); - m_LiveDataBll = new LiveDataBLL(); - m_SettingsBll = new SettingsBLL(); - m_SerializationBll = new SerializationBLL(); - ChildWindows = new ObservableCollection(); Runtime.VisibleStationsChanged += __VisibleStationsChanged; @@ -336,6 +351,13 @@ public int? TrainScheduleNumber } #endregion + #region [IsBildFplInstalled] + public bool IsBildFplInstalled + { + get => m_BildFplInfo?.IsInstalled == true; + } + #endregion + #region - Commands - #region [NewCommand] @@ -398,6 +420,16 @@ public ICommand EstwOnlineCommand } #endregion + #region [BildFplCommand] + public ICommand BildFplCommand + { + get + { + return m_BildFplCommand; + } + } + #endregion + #region [ExitCommand] public ICommand ExitCommand { @@ -983,6 +1015,19 @@ private void __StartEstwOnline() } #endregion + #region [__StartBildFpl] + private void __StartBildFpl() + { + if (m_BildFplInfo == null || !m_BildFplInfo.IsInstalled || m_BildFplInfo.InstallLocation.IsNullOrWhiteSpace()) + return; + + var exePath = Path.Combine(m_BildFplInfo.InstallLocation, "BildFpl_V2.exe"); + + if (File.Exists(exePath)) + Process.Start(exePath); + } + #endregion + #region [__Exit] private void __Exit() { diff --git a/Leibit.Client.WPF/Views/MainView.xaml b/Leibit.Client.WPF/Views/MainView.xaml index ce007dad..76aee3d7 100644 --- a/Leibit.Client.WPF/Views/MainView.xaml +++ b/Leibit.Client.WPF/Views/MainView.xaml @@ -8,6 +8,7 @@ xmlns:core="clr-namespace:Leibit.Core.Client.Common;assembly=Leibit.Core.Client.WPF" xmlns:common="clr-namespace:Leibit.Core.Client.Common;assembly=Leibit.Core.Client.WPF" xmlns:controls="clr-namespace:Leibit.Controls;assembly=Leibit.Controls.WPF" + xmlns:converter="clr-namespace:Leibit.Core.Client.Converter;assembly=Leibit.Core.Client.WPF" Title="LeiBIT für ESTWsim"> @@ -18,6 +19,7 @@ + @@ -71,6 +73,12 @@ + + + + + + @@ -174,7 +182,8 @@ - + + diff --git a/Leibit.Client.WPF/Windows/Settings/ViewModels/PathViewModel.cs b/Leibit.Client.WPF/Windows/Settings/ViewModels/PathViewModel.cs index 4f8ea36b..9dcd6636 100644 --- a/Leibit.Client.WPF/Windows/Settings/ViewModels/PathViewModel.cs +++ b/Leibit.Client.WPF/Windows/Settings/ViewModels/PathViewModel.cs @@ -1,7 +1,12 @@ -using Leibit.Core.Client.BaseClasses; +using Leibit.BLL; +using Leibit.Core.Client.BaseClasses; using Leibit.Core.Client.Commands; +using Leibit.Core.Common; +using Leibit.Entities; using Leibit.Entities.Common; using System; +using System.IO; +using System.Linq; using System.Windows.Forms; using System.Windows.Input; @@ -76,6 +81,42 @@ public ICommand BrowseCommand #endregion + #region - Public methods - + + #region [DeterminePath] + public bool DeterminePath() + { + if (Path.IsNotNullOrWhiteSpace() || m_Estw.ProductName.IsNullOrWhiteSpace()) + return false; + + var bll = new SoftwareInfoBLL(); + var result = bll.GetSoftwareInfo(m_Estw.ProductName); + + if (!result.Succeeded || !result.Result.IsInstalled || result.Result.InstallLocation.IsNullOrWhiteSpace() || !Directory.Exists(result.Result.InstallLocation)) + return false; + + string pattern; + + if (m_Estw.InfrastructureManager == eInfrastructureManager.DB) + pattern = "ESTW *"; + else if (m_Estw.InfrastructureManager == eInfrastructureManager.OEBB) + pattern = "BFZ *"; + else + return false; + + var directories = Directory.EnumerateDirectories(result.Result.InstallLocation, pattern); + var candidates = directories.Where(d => __Normalize(System.IO.Path.GetFileName(d).Substring(pattern.Length - 1)).Equals(__Normalize(m_Estw.Name), StringComparison.OrdinalIgnoreCase)); + + if (candidates.Count() != 1) + return false; + + Path = candidates.Single(); + return true; + } + #endregion + + #endregion + #region - Private methods - private void __Browse() @@ -87,6 +128,11 @@ private void __Browse() Path = Dialog.SelectedPath; } + private string __Normalize(string path) + { + return path.Replace(" ", string.Empty).Replace("-", string.Empty); + } + #endregion } diff --git a/Leibit.Client.WPF/Windows/Settings/ViewModels/SettingsViewModel.cs b/Leibit.Client.WPF/Windows/Settings/ViewModels/SettingsViewModel.cs index b2a3d418..8043c9ac 100644 --- a/Leibit.Client.WPF/Windows/Settings/ViewModels/SettingsViewModel.cs +++ b/Leibit.Client.WPF/Windows/Settings/ViewModels/SettingsViewModel.cs @@ -27,6 +27,7 @@ public class SettingsViewModel : ChildWindowViewModelBase private CommandHandler m_SaveCommand; private CommandHandler m_CancelCommand; private CommandHandler m_EstwOnlineCommand; + private CommandHandler m_DeterminePathsCommand; #endregion #region - Events - @@ -53,6 +54,7 @@ public SettingsViewModel(ObservableCollection areas) m_SaveCommand = new CommandHandler(__Save, false); m_CancelCommand = new CommandHandler(__Cancel, true); m_EstwOnlineCommand = new CommandHandler(__BrowseEstwOnline, true); + m_DeterminePathsCommand = new CommandHandler(__DeterminePaths, true); } #endregion @@ -73,7 +75,27 @@ public ObservableCollection Areas #endregion #region [ShowPathsWarning] - public bool ShowPathsWarning { get; private set; } + public bool ShowPathsWarning + { + get => Get(); + private set => Set(value); + } + #endregion + + #region [ShowPathsInfo] + public bool ShowPathsInfo + { + get => Get(); + private set => Set(value); + } + #endregion + + #region [PathsInfoText] + public string PathsInfoText + { + get => Get(); + private set => Set(value); + } #endregion #region [DelayJustificationEnabled] @@ -434,6 +456,13 @@ public ICommand EstwOnlineCommand } #endregion + #region [DeterminePathsCommand] + public ICommand DeterminePathsCommand + { + get => m_DeterminePathsCommand; + } + #endregion + #endregion #endregion @@ -540,6 +569,28 @@ private void __BrowseEstwOnline() EstwOnlinePath = Dialog.SelectedPath; } + private void __DeterminePaths() + { + var changedPaths = 0; + + foreach (var area in Areas) + foreach (var path in area.Paths) + if (path.DeterminePath()) + changedPaths++; + + if (changedPaths == 0 && ShowPathsWarning) + { + MessageBox.Show("Es konnten keine Pfade automatisch ermittelt werden.", "Warnung", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + + if (changedPaths > 0) + ShowPathsWarning = false; + + PathsInfoText = $"Es wurden {changedPaths} neue Pfade ermittelt."; + ShowPathsInfo = true; + } + #endregion } diff --git a/Leibit.Client.WPF/Windows/Settings/Views/SettingsView.xaml b/Leibit.Client.WPF/Windows/Settings/Views/SettingsView.xaml index c6b5838c..5f984476 100644 --- a/Leibit.Client.WPF/Windows/Settings/Views/SettingsView.xaml +++ b/Leibit.Client.WPF/Windows/Settings/Views/SettingsView.xaml @@ -18,10 +18,21 @@ - Es sind keine Pfade zu ESTWsim konfiguriert. Bitte tragen Sie die Pfade zu den Simulationen ein, die Sie besitzen. + + Es sind keine Pfade zu ESTWsim konfiguriert. Bitte tragen Sie die Pfade zu den Simulationen ein, die Sie besitzen. + + Pfade automatisch ermitteln + - + + + + + + + + @@ -269,15 +280,15 @@ - - - + + + + - -