From 1153fea091105a8ccc1238a78bf852894b398712 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20B=C3=BCchel?= Date: Fri, 21 Jul 2017 10:04:27 +0200 Subject: [PATCH] Enhanced startup- and shutdown-procedure by introducing a stack of IOperations (which are automatically reverted on shutdown or if an error happens during startup). --- SafeExamBrowser.Configuration/WorkingArea.cs | 14 +- .../Behaviour/IOperation.cs | 30 ++++ .../Behaviour/IShutdownController.cs | 4 +- .../Behaviour/IStartupController.cs | 7 +- .../SafeExamBrowser.Contracts.csproj | 1 + .../UserInterface/ISplashScreen.cs | 21 ++- .../BrowserInitializationOperation.cs | 57 ++++++ .../Operations/ProcessMonitoringOperation.cs | 46 +++++ .../TaskbarInitializationOperation.cs | 49 +++++ .../Operations/WorkingAreaOperation.cs | 68 +++++++ .../Behaviour/ShutdownController.cs | 80 ++++----- .../Behaviour/StartupController.cs | 167 ++++++++---------- .../SafeExamBrowser.Core.csproj | 4 + .../SplashScreen.xaml | 2 +- .../SplashScreen.xaml.cs | 20 ++- SafeExamBrowser.UserInterface/Taskbar.xaml | 2 +- .../ViewModels/SplashScreenViewModel.cs | 14 ++ SafeExamBrowser/App.cs | 10 +- 18 files changed, 429 insertions(+), 167 deletions(-) create mode 100644 SafeExamBrowser.Contracts/Behaviour/IOperation.cs create mode 100644 SafeExamBrowser.Core/Behaviour/Operations/BrowserInitializationOperation.cs create mode 100644 SafeExamBrowser.Core/Behaviour/Operations/ProcessMonitoringOperation.cs create mode 100644 SafeExamBrowser.Core/Behaviour/Operations/TaskbarInitializationOperation.cs create mode 100644 SafeExamBrowser.Core/Behaviour/Operations/WorkingAreaOperation.cs diff --git a/SafeExamBrowser.Configuration/WorkingArea.cs b/SafeExamBrowser.Configuration/WorkingArea.cs index 5c2ba20f..74c53ba9 100644 --- a/SafeExamBrowser.Configuration/WorkingArea.cs +++ b/SafeExamBrowser.Configuration/WorkingArea.cs @@ -18,7 +18,7 @@ namespace SafeExamBrowser.Configuration public class WorkingArea : IWorkingArea { private ILogger logger; - private RECT? initial; + private RECT? originalWorkingArea; public WorkingArea(ILogger logger) { @@ -27,9 +27,9 @@ namespace SafeExamBrowser.Configuration public void InitializeFor(ITaskbar taskbar) { - initial = User32.GetWorkingArea(); + originalWorkingArea = User32.GetWorkingArea(); - LogWorkingArea("Saved initial working area", initial.Value); + LogWorkingArea("Saved original working area", originalWorkingArea.Value); var area = new RECT { @@ -39,17 +39,17 @@ namespace SafeExamBrowser.Configuration Bottom = Screen.PrimaryScreen.Bounds.Height - taskbar.GetAbsoluteHeight() }; - LogWorkingArea("Setting new working area", area); + LogWorkingArea("Trying to set new working area", area); User32.SetWorkingArea(area); LogWorkingArea("Working area is now set to", User32.GetWorkingArea()); } public void Reset() { - if (initial.HasValue) + if (originalWorkingArea.HasValue) { - User32.SetWorkingArea(initial.Value); - LogWorkingArea("Restored initial working area", initial.Value); + User32.SetWorkingArea(originalWorkingArea.Value); + LogWorkingArea("Restored original working area", originalWorkingArea.Value); } } diff --git a/SafeExamBrowser.Contracts/Behaviour/IOperation.cs b/SafeExamBrowser.Contracts/Behaviour/IOperation.cs new file mode 100644 index 00000000..805c9530 --- /dev/null +++ b/SafeExamBrowser.Contracts/Behaviour/IOperation.cs @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2017 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +using SafeExamBrowser.Contracts.UserInterface; + +namespace SafeExamBrowser.Contracts.Behaviour +{ + public interface IOperation + { + /// + /// The splash screen to be used to show status information to the user. + /// + ISplashScreen SplashScreen { set; } + + /// + /// Performs the operation. + /// + void Perform(); + + /// + /// Reverts all changes which were made when performing the operation. + /// + void Revert(); + } +} diff --git a/SafeExamBrowser.Contracts/Behaviour/IShutdownController.cs b/SafeExamBrowser.Contracts/Behaviour/IShutdownController.cs index 0da0e1a5..a10dc4a4 100644 --- a/SafeExamBrowser.Contracts/Behaviour/IShutdownController.cs +++ b/SafeExamBrowser.Contracts/Behaviour/IShutdownController.cs @@ -6,6 +6,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +using System.Collections.Generic; + namespace SafeExamBrowser.Contracts.Behaviour { public interface IShutdownController @@ -13,6 +15,6 @@ namespace SafeExamBrowser.Contracts.Behaviour /// /// Reverts any changes performed during the startup or runtime and releases all used resources. /// - void FinalizeApplication(); + void FinalizeApplication(Stack operations); } } diff --git a/SafeExamBrowser.Contracts/Behaviour/IStartupController.cs b/SafeExamBrowser.Contracts/Behaviour/IStartupController.cs index 913402bd..5218c28b 100644 --- a/SafeExamBrowser.Contracts/Behaviour/IStartupController.cs +++ b/SafeExamBrowser.Contracts/Behaviour/IStartupController.cs @@ -6,14 +6,17 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +using System.Collections.Generic; + namespace SafeExamBrowser.Contracts.Behaviour { public interface IStartupController { /// /// Tries to initialize the application. Returns true if the initialization was successful, - /// false otherwise. + /// false otherwise. All operations performed during the startup procedure will be registered + /// to the given out parameter. /// - bool TryInitializeApplication(); + bool TryInitializeApplication(out Stack operations); } } diff --git a/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj b/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj index c28dffe8..74432070 100644 --- a/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj +++ b/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj @@ -42,6 +42,7 @@ + diff --git a/SafeExamBrowser.Contracts/UserInterface/ISplashScreen.cs b/SafeExamBrowser.Contracts/UserInterface/ISplashScreen.cs index 88eff1ab..1a5c2c7c 100644 --- a/SafeExamBrowser.Contracts/UserInterface/ISplashScreen.cs +++ b/SafeExamBrowser.Contracts/UserInterface/ISplashScreen.cs @@ -22,16 +22,27 @@ namespace SafeExamBrowser.Contracts.UserInterface /// void InvokeShow(); + /// + /// Updates the progress bar of the splash screen according to the specified amount. + /// + void Progress(int amount = 1); + + /// + /// Regresses the progress bar of the splash screen according to the specified amount. + /// + void Regress(int amount = 1); + + /// + /// Sets the style of the progress bar to indeterminate, i.e. Progress and + /// Regress won't have any effect when called. + /// + void SetIndeterminate(); + /// /// Set the maximum of the splash screen's progress bar. /// void SetMaxProgress(int max); - /// - /// Updates the progress bar of the splash screen according to the specified amount. - /// - void UpdateProgress(int amount = 1); - /// /// Updates the status text of the splash screen. If the busy flag is set, /// the splash screen will show an animation to indicate a long-running operation. diff --git a/SafeExamBrowser.Core/Behaviour/Operations/BrowserInitializationOperation.cs b/SafeExamBrowser.Core/Behaviour/Operations/BrowserInitializationOperation.cs new file mode 100644 index 00000000..c474329c --- /dev/null +++ b/SafeExamBrowser.Core/Behaviour/Operations/BrowserInitializationOperation.cs @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2017 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +using SafeExamBrowser.Contracts.Behaviour; +using SafeExamBrowser.Contracts.Configuration; +using SafeExamBrowser.Contracts.I18n; +using SafeExamBrowser.Contracts.Logging; +using SafeExamBrowser.Contracts.UserInterface; + +namespace SafeExamBrowser.Core.Behaviour.Operations +{ + class BrowserInitializationOperation : IOperation + { + private IApplicationController browserController; + private IApplicationInfo browserInfo; + private ILogger logger; + private ITaskbar taskbar; + private IUiElementFactory uiFactory; + + public ISplashScreen SplashScreen { private get; set; } + + public BrowserInitializationOperation( + IApplicationController browserController, + IApplicationInfo browserInfo, + ILogger logger, + ITaskbar taskbar, + IUiElementFactory uiFactory) + { + this.browserController = browserController; + this.browserInfo = browserInfo; + this.logger = logger; + this.taskbar = taskbar; + this.uiFactory = uiFactory; + } + + public void Perform() + { + logger.Info("--- Initializing browser ---"); + SplashScreen.UpdateText(Key.SplashScreen_InitializeBrowser); + + var browserButton = uiFactory.CreateApplicationButton(browserInfo); + + browserController.RegisterApplicationButton(browserButton); + taskbar.AddButton(browserButton); + } + + public void Revert() + { + // Nothing to do here so far... + } + } +} diff --git a/SafeExamBrowser.Core/Behaviour/Operations/ProcessMonitoringOperation.cs b/SafeExamBrowser.Core/Behaviour/Operations/ProcessMonitoringOperation.cs new file mode 100644 index 00000000..cba3de03 --- /dev/null +++ b/SafeExamBrowser.Core/Behaviour/Operations/ProcessMonitoringOperation.cs @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2017 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +using SafeExamBrowser.Contracts.Behaviour; +using SafeExamBrowser.Contracts.I18n; +using SafeExamBrowser.Contracts.Logging; +using SafeExamBrowser.Contracts.Monitoring; +using SafeExamBrowser.Contracts.UserInterface; + +namespace SafeExamBrowser.Core.Behaviour.Operations +{ + class ProcessMonitoringOperation : IOperation + { + private ILogger logger; + private IProcessMonitor processMonitor; + + public ISplashScreen SplashScreen { private get; set; } + + public ProcessMonitoringOperation(ILogger logger, IProcessMonitor processMonitor) + { + this.logger = logger; + this.processMonitor = processMonitor; + } + + public void Perform() + { + logger.Info("--- Initializing process monitoring ---"); + SplashScreen.UpdateText(Key.SplashScreen_InitializeProcessMonitoring); + + // TODO + } + + public void Revert() + { + logger.Info("--- Stopping process monitoring ---"); + SplashScreen.UpdateText(Key.SplashScreen_StopProcessMonitoring); + + // TODO + } + } +} diff --git a/SafeExamBrowser.Core/Behaviour/Operations/TaskbarInitializationOperation.cs b/SafeExamBrowser.Core/Behaviour/Operations/TaskbarInitializationOperation.cs new file mode 100644 index 00000000..1639a2f3 --- /dev/null +++ b/SafeExamBrowser.Core/Behaviour/Operations/TaskbarInitializationOperation.cs @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2017 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +using SafeExamBrowser.Contracts.Behaviour; +using SafeExamBrowser.Contracts.Configuration; +using SafeExamBrowser.Contracts.I18n; +using SafeExamBrowser.Contracts.Logging; +using SafeExamBrowser.Contracts.UserInterface; + +namespace SafeExamBrowser.Core.Behaviour.Operations +{ + class TaskbarInitializationOperation : IOperation + { + private ILogger logger; + private ITaskbar taskbar; + private IUiElementFactory uiFactory; + private INotificationInfo aboutInfo; + + public ISplashScreen SplashScreen { private get; set; } + + public TaskbarInitializationOperation(ILogger logger, INotificationInfo aboutInfo, ITaskbar taskbar, IUiElementFactory uiFactory) + { + this.logger = logger; + this.aboutInfo = aboutInfo; + this.taskbar = taskbar; + this.uiFactory = uiFactory; + } + + public void Perform() + { + logger.Info("--- Initializing taskbar ---"); + SplashScreen.UpdateText(Key.SplashScreen_InitializeTaskbar); + + var aboutNotification = uiFactory.CreateNotification(aboutInfo); + + taskbar.AddNotification(aboutNotification); + } + + public void Revert() + { + // Nothing to do here so far... + } + } +} diff --git a/SafeExamBrowser.Core/Behaviour/Operations/WorkingAreaOperation.cs b/SafeExamBrowser.Core/Behaviour/Operations/WorkingAreaOperation.cs new file mode 100644 index 00000000..fcda9b01 --- /dev/null +++ b/SafeExamBrowser.Core/Behaviour/Operations/WorkingAreaOperation.cs @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2017 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +using SafeExamBrowser.Contracts.Behaviour; +using SafeExamBrowser.Contracts.Configuration; +using SafeExamBrowser.Contracts.I18n; +using SafeExamBrowser.Contracts.Logging; +using SafeExamBrowser.Contracts.Monitoring; +using SafeExamBrowser.Contracts.UserInterface; + +namespace SafeExamBrowser.Core.Behaviour.Operations +{ + class WorkingAreaOperation : IOperation + { + private ILogger logger; + private IProcessMonitor processMonitor; + private ITaskbar taskbar; + private IWorkingArea workingArea; + + public ISplashScreen SplashScreen { private get; set; } + + public WorkingAreaOperation(ILogger logger, IProcessMonitor processMonitor, ITaskbar taskbar, IWorkingArea workingArea) + { + this.logger = logger; + this.processMonitor = processMonitor; + this.taskbar = taskbar; + this.workingArea = workingArea; + } + + public void Perform() + { + logger.Info("--- Initializing working area ---"); + SplashScreen.UpdateText(Key.SplashScreen_WaitExplorerTermination, true); + + processMonitor.CloseExplorerShell(); + processMonitor.StartMonitoringExplorer(); + + // TODO + // - Minimizing all open windows + // - Emptying clipboard + + SplashScreen.UpdateText(Key.SplashScreen_InitializeWorkingArea); + workingArea.InitializeFor(taskbar); + } + + public void Revert() + { + logger.Info("--- Restoring working area ---"); + SplashScreen.UpdateText(Key.SplashScreen_RestoreWorkingArea); + + // TODO + // - Restore all windows? + // - Emptying clipboard + + workingArea.Reset(); + + SplashScreen.UpdateText(Key.SplashScreen_WaitExplorerStartup, true); + + processMonitor.StopMonitoringExplorer(); + processMonitor.StartExplorerShell(); + } + } +} diff --git a/SafeExamBrowser.Core/Behaviour/ShutdownController.cs b/SafeExamBrowser.Core/Behaviour/ShutdownController.cs index 4870beec..7b41aa68 100644 --- a/SafeExamBrowser.Core/Behaviour/ShutdownController.cs +++ b/SafeExamBrowser.Core/Behaviour/ShutdownController.cs @@ -30,16 +30,6 @@ namespace SafeExamBrowser.Core.Behaviour private IUiElementFactory uiFactory; private IWorkingArea workingArea; - private IEnumerable ShutdownOperations - { - get - { - yield return StopProcessMonitoring; - yield return RestoreWorkingArea; - yield return FinalizeApplicationLog; - } - } - public ShutdownController( ILogger logger, IMessageBox messageBox, @@ -58,64 +48,62 @@ namespace SafeExamBrowser.Core.Behaviour this.workingArea = workingArea; } - public void FinalizeApplication() + public void FinalizeApplication(Stack operations) { try { InitializeSplashScreen(); - - foreach (var operation in ShutdownOperations) - { - operation(); - splashScreen.UpdateProgress(); - - // TODO: Remove! - Thread.Sleep(250); - } + RevertOperations(operations); + FinalizeApplicationLog(); } catch (Exception e) { - logger.Error($"Failed to finalize application!", e); - messageBox.Show(text.Get(Key.MessageBox_ShutdownError), text.Get(Key.MessageBox_ShutdownErrorTitle), icon: MessageBoxIcon.Error); + LogAndShowException(e); + FinalizeApplicationLog(false); + } + } + + private void RevertOperations(Stack operations) + { + while (operations.Any()) + { + var operation = operations.Pop(); + + operation.SplashScreen = splashScreen; + operation.Revert(); + + splashScreen.Progress(); + + // TODO: Remove! + Thread.Sleep(250); } } private void InitializeSplashScreen() { splashScreen = uiFactory.CreateSplashScreen(settings, text); - splashScreen.SetMaxProgress(ShutdownOperations.Count()); + splashScreen.SetIndeterminate(); splashScreen.UpdateText(Key.SplashScreen_ShutdownProcedure); splashScreen.InvokeShow(); logger.Info("--- Initiating shutdown procedure ---"); } - private void StopProcessMonitoring() + private void LogAndShowException(Exception e) { - logger.Info("--- Stopping process monitoring ---"); - splashScreen.UpdateText(Key.SplashScreen_StopProcessMonitoring); - - // TODO - - processMonitor.StopMonitoringExplorer(); + logger.Error($"Failed to finalize application!", e); + messageBox.Show(text.Get(Key.MessageBox_ShutdownError), text.Get(Key.MessageBox_ShutdownErrorTitle), icon: MessageBoxIcon.Error); } - private void RestoreWorkingArea() + private void FinalizeApplicationLog(bool success = true) { - logger.Info("--- Restoring working area ---"); - splashScreen.UpdateText(Key.SplashScreen_RestoreWorkingArea); - - // TODO - - workingArea.Reset(); - - splashScreen.UpdateText(Key.SplashScreen_WaitExplorerStartup, true); - processMonitor.StartExplorerShell(); - } - - private void FinalizeApplicationLog() - { - logger.Info("--- Application successfully finalized! ---"); - logger.Log($"{Environment.NewLine}# Application terminated at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}"); + if (success) + { + logger.Info("--- Application successfully finalized! ---"); + } + else + { + logger.Log($"{Environment.NewLine}# Application terminated at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}"); + } } } } diff --git a/SafeExamBrowser.Core/Behaviour/StartupController.cs b/SafeExamBrowser.Core/Behaviour/StartupController.cs index a842ce3f..6bb2bec9 100644 --- a/SafeExamBrowser.Core/Behaviour/StartupController.cs +++ b/SafeExamBrowser.Core/Behaviour/StartupController.cs @@ -16,6 +16,7 @@ using SafeExamBrowser.Contracts.I18n; using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.Monitoring; using SafeExamBrowser.Contracts.UserInterface; +using SafeExamBrowser.Core.Behaviour.Operations; namespace SafeExamBrowser.Core.Behaviour { @@ -34,21 +35,7 @@ namespace SafeExamBrowser.Core.Behaviour private IUiElementFactory uiFactory; private IWorkingArea workingArea; - private IEnumerable StartupOperations - { - get - { - yield return HandleCommandLineArguments; - yield return DetectOperatingSystem; - yield return EstablishWcfServiceConnection; - yield return DeactivateWindowsFeatures; - yield return InitializeProcessMonitoring; - yield return InitializeWorkingArea; - yield return InitializeTaskbar; - yield return InitializeBrowser; - yield return FinishInitialization; - } - } + private IEnumerable startupOperations; public StartupController( IApplicationController browserController, @@ -76,33 +63,78 @@ namespace SafeExamBrowser.Core.Behaviour this.workingArea = workingArea; } - public bool TryInitializeApplication() + public bool TryInitializeApplication(out Stack operations) { + operations = new Stack(); + try { + CreateStartupOperations(); + InitializeApplicationLog(); InitializeSplashScreen(); - foreach (var operation in StartupOperations) - { - operation(); - splashScreen.UpdateProgress(); + operations = PerformOperations(); - // TODO: Remove! - Thread.Sleep(250); - } + FinishInitialization(); return true; } catch (Exception e) { - logger.Error($"Failed to initialize application!", e); - messageBox.Show(text.Get(Key.MessageBox_StartupError), text.Get(Key.MessageBox_StartupErrorTitle), icon: MessageBoxIcon.Error); + LogAndShowException(e); + RevertOperations(operations); + FinishInitialization(false); return false; } } + private Stack PerformOperations() + { + var operations = new Stack(); + + foreach (var operation in startupOperations) + { + operations.Push(operation); + + operation.SplashScreen = splashScreen; + operation.Perform(); + + splashScreen.Progress(); + + // TODO: Remove! + Thread.Sleep(250); + } + + return operations; + } + + private void RevertOperations(Stack operations) + { + while (operations.Any()) + { + var operation = operations.Pop(); + + operation.Revert(); + splashScreen.Regress(); + + // TODO: Remove! + Thread.Sleep(250); + } + } + + private void CreateStartupOperations() + { + startupOperations = new IOperation[] + { + new ProcessMonitoringOperation(logger, processMonitor), + new WorkingAreaOperation(logger, processMonitor, taskbar, workingArea), + new TaskbarInitializationOperation(logger, aboutInfo, taskbar, uiFactory), + new BrowserInitializationOperation(browserController, browserInfo, logger, taskbar, uiFactory) + }; + } + private void InitializeApplicationLog() { var titleLine = $"/* {settings.ProgramTitle}, Version {settings.ProgramVersion}{Environment.NewLine}"; @@ -118,84 +150,29 @@ namespace SafeExamBrowser.Core.Behaviour private void InitializeSplashScreen() { splashScreen = uiFactory.CreateSplashScreen(settings, text); - splashScreen.SetMaxProgress(StartupOperations.Count()); + splashScreen.SetMaxProgress(startupOperations.Count()); splashScreen.UpdateText(Key.SplashScreen_StartupProcedure); splashScreen.InvokeShow(); } - private void HandleCommandLineArguments() + private void LogAndShowException(Exception e) { - // TODO + logger.Error($"Failed to initialize application!", e); + messageBox.Show(text.Get(Key.MessageBox_StartupError), text.Get(Key.MessageBox_StartupErrorTitle), icon: MessageBoxIcon.Error); + logger.Info("Reverting operations..."); } - private void DetectOperatingSystem() + private void FinishInitialization(bool success = true) { - // TODO - } - - private void EstablishWcfServiceConnection() - { - // TODO - } - - private void DeactivateWindowsFeatures() - { - // TODO - } - - private void InitializeProcessMonitoring() - { - logger.Info("--- Initializing process monitoring ---"); - splashScreen.UpdateText(Key.SplashScreen_InitializeProcessMonitoring); - - // TODO - - processMonitor.StartMonitoringExplorer(); - } - - private void InitializeWorkingArea() - { - logger.Info("--- Initializing working area ---"); - splashScreen.UpdateText(Key.SplashScreen_WaitExplorerTermination, true); - processMonitor.CloseExplorerShell(); - - // TODO - // - Minimizing all open windows - // - Emptying clipboard - - splashScreen.UpdateText(Key.SplashScreen_InitializeWorkingArea); - workingArea.InitializeFor(taskbar); - } - - private void InitializeTaskbar() - { - logger.Info("--- Initializing taskbar ---"); - splashScreen.UpdateText(Key.SplashScreen_InitializeTaskbar); - - // TODO - - var aboutNotification = uiFactory.CreateNotification(aboutInfo); - - taskbar.AddNotification(aboutNotification); - } - - private void InitializeBrowser() - { - logger.Info("--- Initializing browser ---"); - splashScreen.UpdateText(Key.SplashScreen_InitializeBrowser); - - // TODO - - var browserButton = uiFactory.CreateApplicationButton(browserInfo); - - browserController.RegisterApplicationButton(browserButton); - taskbar.AddButton(browserButton); - } - - private void FinishInitialization() - { - logger.Info("--- Application successfully initialized! ---"); - splashScreen.InvokeClose(); + if (success) + { + logger.Info("--- Application successfully initialized! ---"); + splashScreen.InvokeClose(); + } + else + { + logger.Log($"{Environment.NewLine}# Application terminated at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}"); + } } } } diff --git a/SafeExamBrowser.Core/SafeExamBrowser.Core.csproj b/SafeExamBrowser.Core/SafeExamBrowser.Core.csproj index db22d8c5..ea76dd20 100644 --- a/SafeExamBrowser.Core/SafeExamBrowser.Core.csproj +++ b/SafeExamBrowser.Core/SafeExamBrowser.Core.csproj @@ -40,6 +40,10 @@ + + + + diff --git a/SafeExamBrowser.UserInterface/SplashScreen.xaml b/SafeExamBrowser.UserInterface/SplashScreen.xaml index 51421177..eec07ee3 100644 --- a/SafeExamBrowser.UserInterface/SplashScreen.xaml +++ b/SafeExamBrowser.UserInterface/SplashScreen.xaml @@ -22,7 +22,7 @@ - + diff --git a/SafeExamBrowser.UserInterface/SplashScreen.xaml.cs b/SafeExamBrowser.UserInterface/SplashScreen.xaml.cs index b78b85a3..000b8ab6 100644 --- a/SafeExamBrowser.UserInterface/SplashScreen.xaml.cs +++ b/SafeExamBrowser.UserInterface/SplashScreen.xaml.cs @@ -40,16 +40,26 @@ namespace SafeExamBrowser.UserInterface Dispatcher.Invoke(Show); } + public void Progress(int amount = 1) + { + model.CurrentProgress += amount; + } + + public void Regress(int amount = 1) + { + model.CurrentProgress -= amount; + } + + public void SetIndeterminate() + { + model.IsIndeterminate = true; + } + public void SetMaxProgress(int max) { model.MaxProgress = max; } - public void UpdateProgress(int amount = 1) - { - model.CurrentProgress += amount; - } - public void UpdateText(Key key, bool showBusyIndication = false) { model.StopBusyIndication(); diff --git a/SafeExamBrowser.UserInterface/Taskbar.xaml b/SafeExamBrowser.UserInterface/Taskbar.xaml index 3ae51816..64d5696a 100644 --- a/SafeExamBrowser.UserInterface/Taskbar.xaml +++ b/SafeExamBrowser.UserInterface/Taskbar.xaml @@ -6,7 +6,7 @@ xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Controls" xmlns:s="clr-namespace:System;assembly=mscorlib" mc:Ignorable="d" - Title="Taskbar" Height="40" Width="750" WindowStyle="None" AllowsTransparency="True" Topmost="True" Icon="./Images/SafeExamBrowser.ico"> + Title="Taskbar" Height="40" Width="750" WindowStyle="None" AllowsTransparency="True" Topmost="True" Visibility="Collapsed" Icon="./Images/SafeExamBrowser.ico"> diff --git a/SafeExamBrowser.UserInterface/ViewModels/SplashScreenViewModel.cs b/SafeExamBrowser.UserInterface/ViewModels/SplashScreenViewModel.cs index bcd474ad..90dbbed1 100644 --- a/SafeExamBrowser.UserInterface/ViewModels/SplashScreenViewModel.cs +++ b/SafeExamBrowser.UserInterface/ViewModels/SplashScreenViewModel.cs @@ -14,6 +14,7 @@ namespace SafeExamBrowser.UserInterface.ViewModels class SplashScreenViewModel : INotifyPropertyChanged { private int currentProgress; + private bool isIndeterminate; private int maxProgress; private string status; private Timer busyTimer; @@ -33,6 +34,19 @@ namespace SafeExamBrowser.UserInterface.ViewModels } } + public bool IsIndeterminate + { + get + { + return isIndeterminate; + } + set + { + isIndeterminate = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsIndeterminate))); + } + } + public int MaxProgress { get diff --git a/SafeExamBrowser/App.cs b/SafeExamBrowser/App.cs index 7cc469c5..6a295fb5 100644 --- a/SafeExamBrowser/App.cs +++ b/SafeExamBrowser/App.cs @@ -7,8 +7,10 @@ */ using System; +using System.Collections.Generic; using System.Threading; using System.Windows; +using SafeExamBrowser.Contracts.Behaviour; namespace SafeExamBrowser { @@ -57,12 +59,12 @@ namespace SafeExamBrowser instances.BuildObjectGraph(); - var success = instances.StartupController.TryInitializeApplication(); + var success = instances.StartupController.TryInitializeApplication(out Stack operations); if (success) { MainWindow = instances.Taskbar; - MainWindow.Closing += (o, args) => ShutdownApplication(); + MainWindow.Closing += (o, args) => ShutdownApplication(operations); MainWindow.Show(); } else @@ -71,10 +73,10 @@ namespace SafeExamBrowser } } - private void ShutdownApplication() + private void ShutdownApplication(Stack operations) { MainWindow.Hide(); - instances.ShutdownController.FinalizeApplication(); + instances.ShutdownController.FinalizeApplication(operations); } } }