Index: Application/Riskeer/src/Application.Riskeer/App.cs
===================================================================
diff -u
--- Application/Riskeer/src/Application.Riskeer/App.cs (revision 0)
+++ Application/Riskeer/src/Application.Riskeer/App.cs (revision 76cdcb41e7687ffde95a1eaf235c000f48b707c7)
@@ -0,0 +1,421 @@
+// Copyright (C) Stichting Deltares 2019. All rights reserved.
+//
+// This file is part of Riskeer.
+//
+// Riskeer is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+// All names, logos, and references to "Deltares" are registered trademarks of
+// Stichting Deltares and remain full property of Stichting Deltares at all times.
+// All rights reserved.
+
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Diagnostics;
+using System.DirectoryServices.AccountManagement;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text.RegularExpressions;
+using System.Threading;
+using System.Windows;
+using System.Windows.Controls.Primitives;
+using System.Windows.Forms;
+using Core.Common.Gui;
+using Core.Common.Gui.Appenders;
+using Core.Common.Gui.Forms.MainWindow;
+using Core.Common.Gui.Helpers;
+using Core.Common.Gui.Settings;
+using Core.Common.Util;
+using Core.Common.Util.Settings;
+using Core.Plugins.Chart;
+using Core.Plugins.CommonTools;
+using Core.Plugins.Map;
+using Core.Plugins.ProjectExplorer;
+using log4net;
+using log4net.Appender;
+using Riskeer.ClosingStructures.Plugin;
+using Riskeer.DuneErosion.Plugin;
+using Riskeer.GrassCoverErosionInwards.Plugin;
+using Riskeer.GrassCoverErosionOutwards.Plugin;
+using Riskeer.HeightStructures.Plugin;
+using Riskeer.Integration.Data;
+using Riskeer.Integration.Forms;
+using Riskeer.Integration.Plugin;
+using Riskeer.MacroStabilityInwards.Plugin;
+using Riskeer.Migration;
+using Riskeer.Piping.Plugin;
+using Riskeer.StabilityPointStructures.Plugin;
+using Riskeer.StabilityStoneCover.Plugin;
+using Riskeer.Storage.Core;
+using Riskeer.WaveImpactAsphaltCover.Plugin;
+using CoreCommonGuiResources = Core.Common.Gui.Properties.Resources;
+using MessageBox = System.Windows.MessageBox;
+#if DEVELOPMENT
+using Demo.Riskeer.GUIs;
+
+#endif
+
+namespace Application.Riskeer
+{
+ // Partial class introduced for avoiding problems in relation to dynamically resolving assemblies
+ // (SetupAssemblyResolver must be called before any dependencies are needed).
+ public partial class App
+ {
+ // Start application after this process will exit (used during restart)
+ private const string argumentWaitForProcess = "--wait-for-process=";
+
+ private const int numberOfDaysToKeepLogFiles = 30;
+
+ private static string fileToOpen = string.Empty;
+
+ private static Mutex singleInstanceMutex;
+
+ private static int waitForProcessId = -1;
+
+ private ILog log;
+
+ private GuiCore gui;
+
+ private delegate void ExceptionDelegate(Exception exception);
+
+ protected override void OnExit(ExitEventArgs e)
+ {
+ singleInstanceMutex?.ReleaseMutex();
+ base.OnExit(e);
+ }
+
+ private void Initialize()
+ {
+ Logger.Setup();
+ log = LogManager.GetLogger(typeof(App));
+
+ SettingsHelper.Instance = new RiskeerSettingsHelper();
+ SetLanguage();
+
+ string userDisplay = UserDisplay();
+ log.Info(string.Format(CoreCommonGuiResources.App_Starting_Riskeer_version_0_by_user_0,
+ SettingsHelper.Instance.ApplicationVersion,
+ userDisplay));
+ }
+
+ private void OnStartup(object sender, StartupEventArgs e)
+ {
+ ParseArguments(e.Args);
+
+ Resources.Add(SystemParameters.MenuPopupAnimationKey, PopupAnimation.None);
+
+ WaitForPreviousInstanceToExit();
+ if (ShutdownIfNotFirstInstance())
+ {
+ return;
+ }
+
+ DeleteOldLogFiles();
+
+ var settings = new GuiCoreSettings
+ {
+ SupportEmailAddress = "www.helpdeskwater.nl",
+ SupportPhoneNumber = "+31 (0)88-797 7102",
+ MainWindowTitle = "Riskeer",
+ ManualFilePath = "..\\Gebruikershandleiding Riskeer 19.1.1.pdf"
+ };
+ var mainWindow = new MainWindow();
+ var projectMigrator = new ProjectMigrator(new DialogBasedInquiryHelper(mainWindow));
+ gui = new GuiCore(mainWindow, new StorageSqLite(), projectMigrator, new RiskeerProjectFactory(), settings)
+ {
+ Plugins =
+ {
+ new ProjectExplorerPlugin(),
+ new CommonToolsPlugin(),
+ new RiskeerPlugin(),
+ new ClosingStructuresPlugin(),
+ new StabilityPointStructuresPlugin(),
+ new WaveImpactAsphaltCoverPlugin(),
+ new GrassCoverErosionInwardsPlugin(),
+ new GrassCoverErosionOutwardsPlugin(),
+ new PipingPlugin(),
+ new HeightStructuresPlugin(),
+ new StabilityStoneCoverPlugin(),
+ new DuneErosionPlugin(),
+ new MacroStabilityInwardsPlugin(),
+ new ChartPlugin(),
+ new MapPlugin()
+#if DEVELOPMENT
+ ,
+ new DemoPlugin()
+#endif
+ }
+ };
+
+ RunRiskeer();
+
+ mainWindow.Show();
+ }
+
+ private void RunRiskeer()
+ {
+ string loaderDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
+ if (loaderDirectory != null)
+ {
+ Environment.CurrentDirectory = loaderDirectory;
+ }
+
+ System.Windows.Forms.Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException, true);
+
+ // handle exception from UI thread
+ System.Windows.Forms.Application.ThreadException += Application_ThreadException;
+
+ // handle exception from all threads except UI
+ AppDomain.CurrentDomain.UnhandledException += AppDomain_UnhandledException;
+
+ gui.Run(fileToOpen);
+
+ // Riskeer started, clean-up all possible memory
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+ }
+
+ private void AppDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
+ {
+ Exception exception = e.ExceptionObject as Exception ?? new Exception(CoreCommonGuiResources.App_Unhandled_exception);
+
+ HandleExceptionOnMainThread(exception);
+ }
+
+ private void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
+ {
+ HandleExceptionOnMainThread(e.Exception);
+ }
+
+ private void HandleExceptionOnMainThread(Exception exception)
+ {
+ var control = (Control) gui.MainWindow.PropertyGrid;
+
+ if (control != null && control.InvokeRequired)
+ {
+ // Invoke executes a delegate on the thread that owns _MainForms's underlying window handle.
+ control.Invoke(new ExceptionDelegate(HandleException), exception);
+ }
+ else
+ {
+ HandleException(exception);
+ }
+ }
+
+ private void HandleException(Exception exception)
+ {
+ log.Error(CoreCommonGuiResources.App_Unhandled_exception, exception);
+
+ if (gui?.MainWindow != null)
+ {
+ using (var exceptionDialog = new ExceptionDialog(gui.MainWindow, gui, exception)
+ {
+ OpenLogClicked = () => gui.ApplicationCommands?.OpenLogFileExternal()
+ })
+ {
+ if (exceptionDialog.ShowDialog() == DialogResult.OK)
+ {
+ Restart();
+
+ return;
+ }
+ }
+ }
+
+ Environment.Exit(1);
+ }
+
+ private static void Restart()
+ {
+ Process.Start(typeof(App).Assembly.Location, argumentWaitForProcess + Process.GetCurrentProcess().Id);
+ Environment.Exit(1);
+ }
+
+ ///
+ /// app.config has been configured to use
+ /// to write log files to the Riskeer user data folder. This method deletes the old log files
+ /// that have been written there.
+ ///
+ private void DeleteOldLogFiles()
+ {
+ try
+ {
+ IOUtils.DeleteOldFiles(GetLogFileDirectory(), "*.log", numberOfDaysToKeepLogFiles);
+ }
+ catch (Exception e)
+ {
+ if (e is ArgumentException || e is IOException)
+ {
+ return;
+ }
+
+ throw;
+ }
+ }
+
+ private bool ShutdownIfNotFirstInstance()
+ {
+ var hasMutex = false;
+
+ try
+ {
+ if (!AcquireSingleInstancePerUserMutex())
+ {
+ MessageBox.Show(CoreCommonGuiResources.App_ShutdownIfNotFirstInstance_Cannot_start_multiple_instances_of_Riskeer_Please_close_the_other_instance_first);
+ Shutdown(1);
+ return true; //done here
+ }
+
+ hasMutex = true;
+ }
+ finally
+ {
+ if (!hasMutex)
+ {
+ singleInstanceMutex = null;
+ }
+ }
+
+ return false;
+ }
+
+ private static bool AcquireSingleInstancePerUserMutex()
+ {
+ // Include the user name in the (global) mutex to ensure we limit only the number of instances per
+ // user, not per system (essential on for example Citrix systems).
+ singleInstanceMutex = new Mutex(true, $"Riskeer-single-instance-mutex-{Environment.UserName}", out bool createdNew);
+
+ return createdNew;
+ }
+
+ ///
+ /// If variable waitForProcessId > -1, the application will hold until
+ /// the process with that ID has exited.
+ ///
+ private static void WaitForPreviousInstanceToExit()
+ {
+ // Wait until previous version of Riskeer has exited
+ if (waitForProcessId == -1)
+ {
+ return;
+ }
+
+ try
+ {
+ Process process = Process.GetProcessById(waitForProcessId);
+ process.WaitForExit();
+ }
+ catch
+ {
+ //Ignored, because the process may already be closed
+ }
+ }
+
+ private static bool ParseFileArgument(string potentialPath)
+ {
+ if (potentialPath.Length > 0)
+ {
+ try
+ {
+ IOUtils.ValidateFilePath(potentialPath);
+ fileToOpen = potentialPath;
+ return true;
+ }
+ catch (ArgumentException)
+ {
+ return false;
+ }
+ }
+
+ return false;
+ }
+
+ ///
+ /// Parses the process' start-up parameters.
+ ///
+ /// List of start-up parameters.
+ private static void ParseArguments(IEnumerable arguments)
+ {
+ var argumentWaitForProcessRegex = new Regex("^" + argumentWaitForProcess + @"(?\d+)$", RegexOptions.IgnoreCase);
+ foreach (string arg in arguments)
+ {
+ Match match = argumentWaitForProcessRegex.Match(arg);
+ if (match.Success)
+ {
+ int pid = int.Parse(match.Groups["processId"].Value);
+ if (pid > 0)
+ {
+ waitForProcessId = pid;
+ break;
+ }
+ }
+
+ if (ParseFileArgument(arg))
+ {
+ break;
+ }
+ }
+ }
+
+ private static void SetLanguage()
+ {
+ string language = ConfigurationManager.AppSettings["language"];
+ if (language != null)
+ {
+ var localMachineDateTimeFormat = (DateTimeFormatInfo) Thread.CurrentThread.CurrentCulture.DateTimeFormat.Clone();
+ localMachineDateTimeFormat.DayNames = CultureInfo.InvariantCulture.DateTimeFormat.DayNames;
+ localMachineDateTimeFormat.MonthNames = CultureInfo.InvariantCulture.DateTimeFormat.MonthNames;
+ localMachineDateTimeFormat.AbbreviatedDayNames = CultureInfo.InvariantCulture.DateTimeFormat.AbbreviatedDayNames;
+ localMachineDateTimeFormat.AbbreviatedMonthGenitiveNames = CultureInfo.InvariantCulture.DateTimeFormat.AbbreviatedMonthGenitiveNames;
+ localMachineDateTimeFormat.AbbreviatedMonthNames = CultureInfo.InvariantCulture.DateTimeFormat.AbbreviatedMonthNames;
+
+ var cultureInfo = new CultureInfo(language)
+ {
+ NumberFormat = Thread.CurrentThread.CurrentCulture.NumberFormat,
+ DateTimeFormat = localMachineDateTimeFormat
+ };
+
+ Thread.CurrentThread.CurrentUICulture = cultureInfo;
+ Thread.CurrentThread.CurrentCulture = cultureInfo;
+ }
+ }
+
+ private static string UserDisplay()
+ {
+ try
+ {
+ return $"{UserPrincipal.Current.DisplayName} ({UserPrincipal.Current.SamAccountName})";
+ }
+ catch (SystemException)
+ {
+ // Cannot only catch specified exceptions, as there are some hidden exception
+ // that can be thrown when calling UserPrincipal.Current.
+ return Environment.UserName;
+ }
+ }
+
+ private static string GetLogFileDirectory()
+ {
+ FileAppender fileAppender = LogManager.GetAllRepositories()
+ .SelectMany(r => r.GetAppenders())
+ .OfType()
+ .FirstOrDefault();
+ return string.IsNullOrWhiteSpace(fileAppender?.File)
+ ? string.Empty
+ : Path.GetDirectoryName(fileAppender.File);
+ }
+ }
+}
\ No newline at end of file
Index: Application/Riskeer/src/Application.Riskeer/App.xaml
===================================================================
diff -u -rf9ad6aa27e2c71c187325e65c98d0f4ae6873e0d -r76cdcb41e7687ffde95a1eaf235c000f48b707c7
--- Application/Riskeer/src/Application.Riskeer/App.xaml (.../App.xaml) (revision f9ad6aa27e2c71c187325e65c98d0f4ae6873e0d)
+++ Application/Riskeer/src/Application.Riskeer/App.xaml (.../App.xaml) (revision 76cdcb41e7687ffde95a1eaf235c000f48b707c7)
@@ -23,7 +23,7 @@
+ Startup="OnStartup" ShutdownMode="OnLastWindowClose">
Index: Application/Riskeer/src/Application.Riskeer/App.xaml.cs
===================================================================
diff -u -r284632cdf71f22c0008c9a140e483f9f3b7af5e8 -r76cdcb41e7687ffde95a1eaf235c000f48b707c7
--- Application/Riskeer/src/Application.Riskeer/App.xaml.cs (.../App.xaml.cs) (revision 284632cdf71f22c0008c9a140e483f9f3b7af5e8)
+++ Application/Riskeer/src/Application.Riskeer/App.xaml.cs (.../App.xaml.cs) (revision 76cdcb41e7687ffde95a1eaf235c000f48b707c7)
@@ -20,15 +20,10 @@
// All rights reserved.
using System;
-using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
-using System.Text.RegularExpressions;
-using System.Windows;
-using System.Windows.Controls.Primitives;
using Core.Common.Assembly;
-using Core.Common.Util;
namespace Application.Riskeer
{
@@ -37,35 +32,15 @@
///
public partial class App
{
- // Start application after this process will exit (used during restart)
- private const string argumentWaitForProcess = "--wait-for-process=";
-
- private static string fileToOpen = string.Empty;
-
- private static RiskeerRunner runner;
-
+ ///
+ /// Creates a new instance of .
+ ///
public App()
{
SetupAssemblyResolver();
-
- runner = new RiskeerRunner();
+ Initialize();
}
- protected override void OnExit(ExitEventArgs e)
- {
- runner.OnExit();
- base.OnExit(e);
- }
-
- private void App_Startup(object sender, StartupEventArgs e)
- {
- ParseArguments(e.Args);
-
- Resources.Add(SystemParameters.MenuPopupAnimationKey, PopupAnimation.None);
-
- runner.Run(fileToOpen, this);
- }
-
private static void SetupAssemblyResolver()
{
string assemblyDirectory = Path.Combine(GetApplicationDirectory(), "Built-in", "Managed");
@@ -90,52 +65,6 @@
}
}
- private static bool ParseFileArgument(string potentialPath)
- {
- if (potentialPath.Length > 0)
- {
- try
- {
- IOUtils.ValidateFilePath(potentialPath);
- fileToOpen = potentialPath;
- return true;
- }
- catch (ArgumentException)
- {
- return false;
- }
- }
-
- return false;
- }
-
- ///
- /// Parses the process' start-up parameters.
- ///
- /// List of start-up parameters.
- private static void ParseArguments(IEnumerable arguments)
- {
- var argumentWaitForProcessRegex = new Regex("^" + argumentWaitForProcess + @"(?\d+)$", RegexOptions.IgnoreCase);
- foreach (string arg in arguments)
- {
- Match match = argumentWaitForProcessRegex.Match(arg);
- if (match.Success)
- {
- int pid = int.Parse(match.Groups["processId"].Value);
- if (pid > 0)
- {
- RiskeerRunner.WaitForProcessId = pid;
- break;
- }
- }
-
- if (ParseFileArgument(arg))
- {
- break;
- }
- }
- }
-
private static string GetApplicationDirectory()
{
DirectoryInfo executingAssemblyDirectoryInfo = Directory.GetParent(Assembly.GetExecutingAssembly().Location);
Fisheye: Tag 76cdcb41e7687ffde95a1eaf235c000f48b707c7 refers to a dead (removed) revision in file `Application/Riskeer/src/Application.Riskeer/RiskeerRunner.cs'.
Fisheye: No comparison available. Pass `N' to diff?