From 5b577344065902a0241cac9b84103cd8e554b688 Mon Sep 17 00:00:00 2001 From: dbuechel Date: Fri, 2 Feb 2018 09:18:35 +0100 Subject: [PATCH] SEBWIN-219: Finally found appropriate solution for handling bootstrap- and session-operations. --- .../Operations/BrowserOperationTests.cs | 7 +- .../ClientControllerOperationTests.cs | 8 +- .../Operations/ClipboardOperationTests.cs | 8 +- .../DisplayMonitorOperationTests.cs | 8 +- .../KeyboardInterceptorOperationTests.cs | 8 +- .../MouseInterceptorOperationTests.cs | 8 +- .../ProcessMonitorOperationTests.cs | 8 +- .../Operations/TaskbarOperationTests.cs | 7 +- .../Operations/WindowMonitorOperationTests.cs | 8 +- .../Behaviour/Operations/BrowserOperation.cs | 6 +- .../Operations/ClientControllerOperation.cs | 6 +- .../Operations/ClipboardOperation.cs | 4 +- .../Operations/DisplayMonitorOperation.cs | 6 +- .../KeyboardInterceptorOperation.cs | 6 +- .../Operations/MouseInterceptorOperation.cs | 6 +- .../Operations/ProcessMonitorOperation.cs | 10 +- .../Behaviour/Operations/TaskbarOperation.cs | 6 +- .../Operations/WindowMonitorOperation.cs | 6 +- .../Behaviour/IRuntimeController.cs | 5 +- .../Behaviour/Operations/IOperation.cs | 6 +- .../Operations/IOperationSequence.cs | 15 +- SafeExamBrowser.Contracts/I18n/TextKey.cs | 1 - .../SafeExamBrowser.Contracts.csproj | 1 + .../UserInterface/IProgressIndicator.cs | 45 ++++ .../UserInterface/IRuntimeWindow.cs | 13 +- .../UserInterface/ISplashScreen.cs | 30 +-- .../Operations/I18nOperationTests.cs | 8 +- .../Operations/OperationSequenceTests.cs | 225 +++++++++++++++--- .../Behaviour/Operations/I18nOperation.cs | 2 +- .../Behaviour/Operations/OperationSequence.cs | 109 +++++---- SafeExamBrowser.Core/I18n/Text.xml | 3 - .../Operations/ConfigurationOperationTests.cs | 47 +--- .../Operations/ServiceOperationTests.cs | 9 +- SafeExamBrowser.Runtime/App.cs | 2 +- .../Operations/ConfigurationOperation.cs | 6 +- .../Operations/KioskModeOperation.cs | 6 +- .../Behaviour/Operations/ServiceOperation.cs | 6 +- .../Behaviour/RuntimeController.cs | 104 +++++--- SafeExamBrowser.Runtime/CompositionRoot.cs | 20 +- .../RuntimeWindow.xaml | 9 +- .../RuntimeWindow.xaml.cs | 66 +++-- ...feExamBrowser.UserInterface.Classic.csproj | 2 +- .../SplashScreen.xaml.cs | 9 +- ...Model.cs => ProgressIndicatorViewModel.cs} | 11 +- .../ViewModels/RuntimeWindowViewModel.cs | 59 ++--- .../SplashScreen.xaml.cs | 7 +- 46 files changed, 559 insertions(+), 393 deletions(-) create mode 100644 SafeExamBrowser.Contracts/UserInterface/IProgressIndicator.cs rename SafeExamBrowser.UserInterface.Classic/ViewModels/{SplashScreenViewModel.cs => ProgressIndicatorViewModel.cs} (86%) diff --git a/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/BrowserOperationTests.cs b/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/BrowserOperationTests.cs index 2d96dca4..690fe4d9 100644 --- a/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/BrowserOperationTests.cs +++ b/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/BrowserOperationTests.cs @@ -23,7 +23,6 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations private Mock controllerMock; private Mock appInfoMock; private Mock loggerMock; - private Mock splashScreenMock; private Mock taskbarMock; private Mock uiFactoryMock; @@ -35,14 +34,10 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations controllerMock = new Mock(); appInfoMock = new Mock(); loggerMock = new Mock(); - splashScreenMock = new Mock(); taskbarMock = new Mock(); uiFactoryMock = new Mock(); - sut = new BrowserOperation(controllerMock.Object, appInfoMock.Object, loggerMock.Object, taskbarMock.Object, uiFactoryMock.Object) - { - SplashScreen = splashScreenMock.Object - }; + sut = new BrowserOperation(controllerMock.Object, appInfoMock.Object, loggerMock.Object, taskbarMock.Object, uiFactoryMock.Object); } [TestMethod] diff --git a/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/ClientControllerOperationTests.cs b/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/ClientControllerOperationTests.cs index ebffe149..862b79d8 100644 --- a/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/ClientControllerOperationTests.cs +++ b/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/ClientControllerOperationTests.cs @@ -11,7 +11,6 @@ using Moq; using SafeExamBrowser.Client.Behaviour.Operations; using SafeExamBrowser.Contracts.Behaviour; using SafeExamBrowser.Contracts.Logging; -using SafeExamBrowser.Contracts.UserInterface; namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations { @@ -20,7 +19,6 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations { private Mock loggerMock; private Mock clientControllerMock; - private Mock splashScreenMock; private ClientControllerOperation sut; @@ -29,12 +27,8 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations { loggerMock = new Mock(); clientControllerMock = new Mock(); - splashScreenMock = new Mock(); - sut = new ClientControllerOperation(clientControllerMock.Object, loggerMock.Object) - { - SplashScreen = splashScreenMock.Object - }; + sut = new ClientControllerOperation(clientControllerMock.Object, loggerMock.Object); } [TestMethod] diff --git a/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/ClipboardOperationTests.cs b/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/ClipboardOperationTests.cs index aff30aad..2189efbe 100644 --- a/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/ClipboardOperationTests.cs +++ b/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/ClipboardOperationTests.cs @@ -10,7 +10,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using SafeExamBrowser.Client.Behaviour.Operations; using SafeExamBrowser.Contracts.Logging; -using SafeExamBrowser.Contracts.UserInterface; using SafeExamBrowser.Contracts.WindowsApi; namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations @@ -20,7 +19,6 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations { private Mock loggerMock; private Mock nativeMethodsMock; - private Mock splashScreenMock; private ClipboardOperation sut; @@ -29,12 +27,8 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations { loggerMock = new Mock(); nativeMethodsMock = new Mock(); - splashScreenMock = new Mock(); - sut = new ClipboardOperation(loggerMock.Object, nativeMethodsMock.Object) - { - SplashScreen = splashScreenMock.Object - }; + sut = new ClipboardOperation(loggerMock.Object, nativeMethodsMock.Object); } [TestMethod] diff --git a/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/DisplayMonitorOperationTests.cs b/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/DisplayMonitorOperationTests.cs index d09bc867..71fba235 100644 --- a/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/DisplayMonitorOperationTests.cs +++ b/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/DisplayMonitorOperationTests.cs @@ -11,7 +11,6 @@ using Moq; using SafeExamBrowser.Client.Behaviour.Operations; using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.Monitoring; -using SafeExamBrowser.Contracts.UserInterface; using SafeExamBrowser.Contracts.UserInterface.Taskbar; namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations @@ -21,7 +20,6 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations { private Mock displayMonitorMock; private Mock loggerMock; - private Mock splashScreenMock; private Mock taskbarMock; private DisplayMonitorOperation sut; @@ -31,13 +29,9 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations { loggerMock = new Mock(); displayMonitorMock = new Mock(); - splashScreenMock = new Mock(); taskbarMock = new Mock(); - sut = new DisplayMonitorOperation(displayMonitorMock.Object, loggerMock.Object, taskbarMock.Object) - { - SplashScreen = splashScreenMock.Object - }; + sut = new DisplayMonitorOperation(displayMonitorMock.Object, loggerMock.Object, taskbarMock.Object); } [TestMethod] diff --git a/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/KeyboardInterceptorOperationTests.cs b/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/KeyboardInterceptorOperationTests.cs index 8dbc8c09..30cfce8d 100644 --- a/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/KeyboardInterceptorOperationTests.cs +++ b/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/KeyboardInterceptorOperationTests.cs @@ -11,7 +11,6 @@ using Moq; using SafeExamBrowser.Client.Behaviour.Operations; using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.Monitoring; -using SafeExamBrowser.Contracts.UserInterface; using SafeExamBrowser.Contracts.WindowsApi; namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations @@ -22,7 +21,6 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations private Mock keyboardInterceptorMock; private Mock loggerMock; private Mock nativeMethodsMock; - private Mock splashScreenMock; private KeyboardInterceptorOperation sut; @@ -32,12 +30,8 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations keyboardInterceptorMock = new Mock(); loggerMock = new Mock(); nativeMethodsMock = new Mock(); - splashScreenMock = new Mock(); - sut = new KeyboardInterceptorOperation(keyboardInterceptorMock.Object, loggerMock.Object, nativeMethodsMock.Object) - { - SplashScreen = splashScreenMock.Object - }; + sut = new KeyboardInterceptorOperation(keyboardInterceptorMock.Object, loggerMock.Object, nativeMethodsMock.Object); } [TestMethod] diff --git a/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/MouseInterceptorOperationTests.cs b/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/MouseInterceptorOperationTests.cs index 270c57eb..6c0d3eaa 100644 --- a/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/MouseInterceptorOperationTests.cs +++ b/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/MouseInterceptorOperationTests.cs @@ -11,7 +11,6 @@ using Moq; using SafeExamBrowser.Client.Behaviour.Operations; using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.Monitoring; -using SafeExamBrowser.Contracts.UserInterface; using SafeExamBrowser.Contracts.WindowsApi; namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations @@ -22,7 +21,6 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations private Mock mouseInterceptorMock; private Mock loggerMock; private Mock nativeMethodsMock; - private Mock splashScreenMock; private MouseInterceptorOperation sut; @@ -32,12 +30,8 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations mouseInterceptorMock = new Mock(); loggerMock = new Mock(); nativeMethodsMock = new Mock(); - splashScreenMock = new Mock(); - sut = new MouseInterceptorOperation(loggerMock.Object, mouseInterceptorMock.Object, nativeMethodsMock.Object) - { - SplashScreen = splashScreenMock.Object - }; + sut = new MouseInterceptorOperation(loggerMock.Object, mouseInterceptorMock.Object, nativeMethodsMock.Object); } [TestMethod] diff --git a/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/ProcessMonitorOperationTests.cs b/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/ProcessMonitorOperationTests.cs index aebde941..20d75fa7 100644 --- a/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/ProcessMonitorOperationTests.cs +++ b/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/ProcessMonitorOperationTests.cs @@ -11,7 +11,6 @@ using Moq; using SafeExamBrowser.Client.Behaviour.Operations; using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.Monitoring; -using SafeExamBrowser.Contracts.UserInterface; namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations { @@ -20,7 +19,6 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations { private Mock loggerMock; private Mock processMonitorMock; - private Mock splashScreenMock; private ProcessMonitorOperation sut; @@ -29,12 +27,8 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations { loggerMock = new Mock(); processMonitorMock = new Mock(); - splashScreenMock = new Mock(); - sut = new ProcessMonitorOperation(loggerMock.Object, processMonitorMock.Object) - { - SplashScreen = splashScreenMock.Object - }; + sut = new ProcessMonitorOperation(loggerMock.Object, processMonitorMock.Object); } [TestMethod] diff --git a/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/TaskbarOperationTests.cs b/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/TaskbarOperationTests.cs index 184fd0bb..0e01539a 100644 --- a/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/TaskbarOperationTests.cs +++ b/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/TaskbarOperationTests.cs @@ -24,7 +24,6 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations { private Mock loggerMock; private Mock settingsMock; - private Mock splashScreenMock; private Mock> keyboardLayoutMock; private Mock> powerSupplyMock; private Mock> wirelessNetworkMock; @@ -40,7 +39,6 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations { loggerMock = new Mock(); settingsMock = new Mock(); - splashScreenMock = new Mock(); keyboardLayoutMock = new Mock>(); powerSupplyMock = new Mock>(); wirelessNetworkMock = new Mock>(); @@ -64,10 +62,7 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations systemInfoMock.Object, taskbarMock.Object, textMock.Object, - uiFactoryMock.Object) - { - SplashScreen = splashScreenMock.Object - }; + uiFactoryMock.Object); } [TestMethod] diff --git a/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/WindowMonitorOperationTests.cs b/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/WindowMonitorOperationTests.cs index f2b26405..66a47178 100644 --- a/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/WindowMonitorOperationTests.cs +++ b/SafeExamBrowser.Client.UnitTests/Behaviour/Operations/WindowMonitorOperationTests.cs @@ -11,7 +11,6 @@ using Moq; using SafeExamBrowser.Client.Behaviour.Operations; using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.Monitoring; -using SafeExamBrowser.Contracts.UserInterface; namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations { @@ -19,7 +18,6 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations public class WindowMonitorOperationTests { private Mock loggerMock; - private Mock splashScreenMock; private Mock windowMonitorMock; private WindowMonitorOperation sut; @@ -28,13 +26,9 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations public void Initialize() { loggerMock = new Mock(); - splashScreenMock = new Mock(); windowMonitorMock = new Mock(); - sut = new WindowMonitorOperation(loggerMock.Object, windowMonitorMock.Object) - { - SplashScreen = splashScreenMock.Object - }; + sut = new WindowMonitorOperation(loggerMock.Object, windowMonitorMock.Object); } [TestMethod] diff --git a/SafeExamBrowser.Client/Behaviour/Operations/BrowserOperation.cs b/SafeExamBrowser.Client/Behaviour/Operations/BrowserOperation.cs index 45bf8879..9975cfaa 100644 --- a/SafeExamBrowser.Client/Behaviour/Operations/BrowserOperation.cs +++ b/SafeExamBrowser.Client/Behaviour/Operations/BrowserOperation.cs @@ -25,7 +25,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations private IUserInterfaceFactory uiFactory; public bool Abort { get; private set; } - public ISplashScreen SplashScreen { private get; set; } + public IProgressIndicator ProgressIndicator { private get; set; } public BrowserOperation( IApplicationController browserController, @@ -44,7 +44,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations public void Perform() { logger.Info("Initializing browser..."); - SplashScreen.UpdateText(TextKey.SplashScreen_InitializeBrowser, true); + ProgressIndicator?.UpdateText(TextKey.SplashScreen_InitializeBrowser, true); var browserButton = uiFactory.CreateApplicationButton(browserInfo); @@ -62,7 +62,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations public void Revert() { logger.Info("Terminating browser..."); - SplashScreen.UpdateText(TextKey.SplashScreen_TerminateBrowser, true); + ProgressIndicator?.UpdateText(TextKey.SplashScreen_TerminateBrowser, true); browserController.Terminate(); } diff --git a/SafeExamBrowser.Client/Behaviour/Operations/ClientControllerOperation.cs b/SafeExamBrowser.Client/Behaviour/Operations/ClientControllerOperation.cs index b21e680b..d5c44a44 100644 --- a/SafeExamBrowser.Client/Behaviour/Operations/ClientControllerOperation.cs +++ b/SafeExamBrowser.Client/Behaviour/Operations/ClientControllerOperation.cs @@ -20,7 +20,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations private IClientController controller; public bool Abort { get; private set; } - public ISplashScreen SplashScreen { private get; set; } + public IProgressIndicator ProgressIndicator { private get; set; } public ClientControllerOperation(IClientController controller, ILogger logger) { @@ -31,7 +31,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations public void Perform() { logger.Info("Starting event handling..."); - SplashScreen.UpdateText(TextKey.SplashScreen_StartEventHandling); + ProgressIndicator?.UpdateText(TextKey.SplashScreen_StartEventHandling); controller.Start(); } @@ -44,7 +44,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations public void Revert() { logger.Info("Stopping event handling..."); - SplashScreen.UpdateText(TextKey.SplashScreen_StopEventHandling); + ProgressIndicator?.UpdateText(TextKey.SplashScreen_StopEventHandling); controller.Stop(); } diff --git a/SafeExamBrowser.Client/Behaviour/Operations/ClipboardOperation.cs b/SafeExamBrowser.Client/Behaviour/Operations/ClipboardOperation.cs index 58982947..f418c0c7 100644 --- a/SafeExamBrowser.Client/Behaviour/Operations/ClipboardOperation.cs +++ b/SafeExamBrowser.Client/Behaviour/Operations/ClipboardOperation.cs @@ -20,7 +20,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations private INativeMethods nativeMethods; public bool Abort { get; private set; } - public ISplashScreen SplashScreen { private get; set; } + public IProgressIndicator ProgressIndicator { private get; set; } public ClipboardOperation(ILogger logger, INativeMethods nativeMethods) { @@ -46,7 +46,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations private void EmptyClipboard() { logger.Info("Emptying clipboard..."); - SplashScreen.UpdateText(TextKey.SplashScreen_EmptyClipboard); + ProgressIndicator?.UpdateText(TextKey.SplashScreen_EmptyClipboard); nativeMethods.EmptyClipboard(); } diff --git a/SafeExamBrowser.Client/Behaviour/Operations/DisplayMonitorOperation.cs b/SafeExamBrowser.Client/Behaviour/Operations/DisplayMonitorOperation.cs index e9ae0c49..305ae813 100644 --- a/SafeExamBrowser.Client/Behaviour/Operations/DisplayMonitorOperation.cs +++ b/SafeExamBrowser.Client/Behaviour/Operations/DisplayMonitorOperation.cs @@ -22,7 +22,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations private ITaskbar taskbar; public bool Abort { get; private set; } - public ISplashScreen SplashScreen { private get; set; } + public IProgressIndicator ProgressIndicator { private get; set; } public DisplayMonitorOperation(IDisplayMonitor displayMonitor, ILogger logger, ITaskbar taskbar) { @@ -34,7 +34,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations public void Perform() { logger.Info("Initializing working area..."); - SplashScreen.UpdateText(TextKey.SplashScreen_InitializeWorkingArea); + ProgressIndicator?.UpdateText(TextKey.SplashScreen_InitializeWorkingArea); displayMonitor.PreventSleepMode(); displayMonitor.InitializePrimaryDisplay(taskbar.GetAbsoluteHeight()); @@ -49,7 +49,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations public void Revert() { logger.Info("Restoring working area..."); - SplashScreen.UpdateText(TextKey.SplashScreen_RestoreWorkingArea); + ProgressIndicator?.UpdateText(TextKey.SplashScreen_RestoreWorkingArea); displayMonitor.StopMonitoringDisplayChanges(); displayMonitor.ResetPrimaryDisplay(); diff --git a/SafeExamBrowser.Client/Behaviour/Operations/KeyboardInterceptorOperation.cs b/SafeExamBrowser.Client/Behaviour/Operations/KeyboardInterceptorOperation.cs index cb2216fb..f33d57bb 100644 --- a/SafeExamBrowser.Client/Behaviour/Operations/KeyboardInterceptorOperation.cs +++ b/SafeExamBrowser.Client/Behaviour/Operations/KeyboardInterceptorOperation.cs @@ -22,7 +22,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations private INativeMethods nativeMethods; public bool Abort { get; private set; } - public ISplashScreen SplashScreen { private get; set; } + public IProgressIndicator ProgressIndicator { private get; set; } public KeyboardInterceptorOperation( IKeyboardInterceptor keyboardInterceptor, @@ -37,7 +37,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations public void Perform() { logger.Info("Starting keyboard interception..."); - SplashScreen.UpdateText(TextKey.SplashScreen_StartKeyboardInterception); + ProgressIndicator?.UpdateText(TextKey.SplashScreen_StartKeyboardInterception); nativeMethods.RegisterKeyboardHook(keyboardInterceptor); } @@ -50,7 +50,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations public void Revert() { logger.Info("Stopping keyboard interception..."); - SplashScreen.UpdateText(TextKey.SplashScreen_StopKeyboardInterception); + ProgressIndicator?.UpdateText(TextKey.SplashScreen_StopKeyboardInterception); nativeMethods.DeregisterKeyboardHook(keyboardInterceptor); } diff --git a/SafeExamBrowser.Client/Behaviour/Operations/MouseInterceptorOperation.cs b/SafeExamBrowser.Client/Behaviour/Operations/MouseInterceptorOperation.cs index 70b29cca..fd238313 100644 --- a/SafeExamBrowser.Client/Behaviour/Operations/MouseInterceptorOperation.cs +++ b/SafeExamBrowser.Client/Behaviour/Operations/MouseInterceptorOperation.cs @@ -22,7 +22,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations private INativeMethods nativeMethods; public bool Abort { get; private set; } - public ISplashScreen SplashScreen { private get; set; } + public IProgressIndicator ProgressIndicator { private get; set; } public MouseInterceptorOperation( ILogger logger, @@ -37,7 +37,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations public void Perform() { logger.Info("Starting mouse interception..."); - SplashScreen.UpdateText(TextKey.SplashScreen_StartMouseInterception); + ProgressIndicator?.UpdateText(TextKey.SplashScreen_StartMouseInterception); nativeMethods.RegisterMouseHook(mouseInterceptor); } @@ -50,7 +50,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations public void Revert() { logger.Info("Stopping mouse interception..."); - SplashScreen.UpdateText(TextKey.SplashScreen_StopMouseInterception); + ProgressIndicator?.UpdateText(TextKey.SplashScreen_StopMouseInterception); nativeMethods.DeregisterMouseHook(mouseInterceptor); } diff --git a/SafeExamBrowser.Client/Behaviour/Operations/ProcessMonitorOperation.cs b/SafeExamBrowser.Client/Behaviour/Operations/ProcessMonitorOperation.cs index 815a02ee..9225eefb 100644 --- a/SafeExamBrowser.Client/Behaviour/Operations/ProcessMonitorOperation.cs +++ b/SafeExamBrowser.Client/Behaviour/Operations/ProcessMonitorOperation.cs @@ -20,7 +20,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations private IProcessMonitor processMonitor; public bool Abort { get; private set; } - public ISplashScreen SplashScreen { private get; set; } + public IProgressIndicator ProgressIndicator { private get; set; } public ProcessMonitorOperation(ILogger logger, IProcessMonitor processMonitor) { @@ -31,12 +31,12 @@ namespace SafeExamBrowser.Client.Behaviour.Operations public void Perform() { logger.Info("Initializing process monitoring..."); - SplashScreen.UpdateText(TextKey.SplashScreen_WaitExplorerTermination, true); + ProgressIndicator?.UpdateText(TextKey.SplashScreen_WaitExplorerTermination, true); processMonitor.CloseExplorerShell(); processMonitor.StartMonitoringExplorer(); - SplashScreen.UpdateText(TextKey.SplashScreen_InitializeProcessMonitoring); + ProgressIndicator?.UpdateText(TextKey.SplashScreen_InitializeProcessMonitoring); // TODO } @@ -49,11 +49,11 @@ namespace SafeExamBrowser.Client.Behaviour.Operations public void Revert() { logger.Info("Stopping process monitoring..."); - SplashScreen.UpdateText(TextKey.SplashScreen_StopProcessMonitoring); + ProgressIndicator?.UpdateText(TextKey.SplashScreen_StopProcessMonitoring); // TODO - SplashScreen.UpdateText(TextKey.SplashScreen_WaitExplorerStartup, true); + ProgressIndicator?.UpdateText(TextKey.SplashScreen_WaitExplorerStartup, true); processMonitor.StopMonitoringExplorer(); processMonitor.StartExplorerShell(); diff --git a/SafeExamBrowser.Client/Behaviour/Operations/TaskbarOperation.cs b/SafeExamBrowser.Client/Behaviour/Operations/TaskbarOperation.cs index 7fe7ca4b..52842a33 100644 --- a/SafeExamBrowser.Client/Behaviour/Operations/TaskbarOperation.cs +++ b/SafeExamBrowser.Client/Behaviour/Operations/TaskbarOperation.cs @@ -33,7 +33,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations private IText text; public bool Abort { get; private set; } - public ISplashScreen SplashScreen { private get; set; } + public IProgressIndicator ProgressIndicator { private get; set; } public TaskbarOperation( ILogger logger, @@ -60,7 +60,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations public void Perform() { logger.Info("Initializing taskbar..."); - SplashScreen.UpdateText(TextKey.SplashScreen_InitializeTaskbar); + ProgressIndicator?.UpdateText(TextKey.SplashScreen_InitializeTaskbar); if (settings.AllowApplicationLog) { @@ -91,7 +91,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations public void Revert() { logger.Info("Terminating taskbar..."); - SplashScreen.UpdateText(TextKey.SplashScreen_TerminateTaskbar); + ProgressIndicator?.UpdateText(TextKey.SplashScreen_TerminateTaskbar); if (settings.AllowApplicationLog) { diff --git a/SafeExamBrowser.Client/Behaviour/Operations/WindowMonitorOperation.cs b/SafeExamBrowser.Client/Behaviour/Operations/WindowMonitorOperation.cs index e8d370ae..221d5cf4 100644 --- a/SafeExamBrowser.Client/Behaviour/Operations/WindowMonitorOperation.cs +++ b/SafeExamBrowser.Client/Behaviour/Operations/WindowMonitorOperation.cs @@ -20,7 +20,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations private IWindowMonitor windowMonitor; public bool Abort { get; private set; } - public ISplashScreen SplashScreen { private get; set; } + public IProgressIndicator ProgressIndicator { private get; set; } public WindowMonitorOperation(ILogger logger, IWindowMonitor windowMonitor) { @@ -31,7 +31,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations public void Perform() { logger.Info("Initializing window monitoring..."); - SplashScreen.UpdateText(TextKey.SplashScreen_InitializeWindowMonitoring); + ProgressIndicator?.UpdateText(TextKey.SplashScreen_InitializeWindowMonitoring); windowMonitor.HideAllWindows(); windowMonitor.StartMonitoringWindows(); @@ -45,7 +45,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations public void Revert() { logger.Info("Stopping window monitoring..."); - SplashScreen.UpdateText(TextKey.SplashScreen_StopWindowMonitoring); + ProgressIndicator?.UpdateText(TextKey.SplashScreen_StopWindowMonitoring); windowMonitor.StopMonitoringWindows(); windowMonitor.RestoreHiddenWindows(); diff --git a/SafeExamBrowser.Contracts/Behaviour/IRuntimeController.cs b/SafeExamBrowser.Contracts/Behaviour/IRuntimeController.cs index a885540e..e40a3518 100644 --- a/SafeExamBrowser.Contracts/Behaviour/IRuntimeController.cs +++ b/SafeExamBrowser.Contracts/Behaviour/IRuntimeController.cs @@ -6,9 +6,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using System.Collections.Generic; -using SafeExamBrowser.Contracts.Behaviour.Operations; - namespace SafeExamBrowser.Contracts.Behaviour { public interface IRuntimeController @@ -21,6 +18,6 @@ namespace SafeExamBrowser.Contracts.Behaviour /// /// Tries to start the runtime. Returns true if successful, otherwise false. /// - bool TryStart(Queue operations); + bool TryStart(); } } diff --git a/SafeExamBrowser.Contracts/Behaviour/Operations/IOperation.cs b/SafeExamBrowser.Contracts/Behaviour/Operations/IOperation.cs index 39ebc29a..32cd9cdb 100644 --- a/SafeExamBrowser.Contracts/Behaviour/Operations/IOperation.cs +++ b/SafeExamBrowser.Contracts/Behaviour/Operations/IOperation.cs @@ -13,14 +13,14 @@ namespace SafeExamBrowser.Contracts.Behaviour.Operations public interface IOperation { /// - /// Determines whether the procedure to which this operation belongs should be aborted. + /// Determines whether the procedure to which this operation belongs to should be aborted. /// bool Abort { get; } /// - /// The splash screen to be used to show status information to the user. + /// The progress indicator to be used to show status information to the user. Will be ignored if null. /// - ISplashScreen SplashScreen { set; } + IProgressIndicator ProgressIndicator { set; } /// /// Performs the operation. diff --git a/SafeExamBrowser.Contracts/Behaviour/Operations/IOperationSequence.cs b/SafeExamBrowser.Contracts/Behaviour/Operations/IOperationSequence.cs index 240b63e6..b0f94591 100644 --- a/SafeExamBrowser.Contracts/Behaviour/Operations/IOperationSequence.cs +++ b/SafeExamBrowser.Contracts/Behaviour/Operations/IOperationSequence.cs @@ -6,24 +6,29 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using System.Collections.Generic; +using SafeExamBrowser.Contracts.UserInterface; namespace SafeExamBrowser.Contracts.Behaviour.Operations { public interface IOperationSequence { /// - /// Tries to perform the given sequence of operations. Returns true if the procedure was successful, false otherwise. + /// The progress indicator to be used when performing any action. Will be ignored if null. /// - bool TryPerform(Queue operations); + IProgressIndicator ProgressIndicator { set; } /// - /// Tries to repeat all operations of this sequence. Returns true if the procedure was successful, false otherwise. + /// Tries to perform the operations of this sequence. Returns true if the procedure was successful, false otherwise. + /// + bool TryPerform(); + + /// + /// Tries to repeat the operations of this sequence. Returns true if the procedure was successful, false otherwise. /// bool TryRepeat(); /// - /// Tries to revert all operations of this sequence. Returns true if the procedure was successful, false otherwise. + /// Tries to revert the operations of this sequence. Returns true if the procedure was successful, false otherwise. /// bool TryRevert(); } diff --git a/SafeExamBrowser.Contracts/I18n/TextKey.cs b/SafeExamBrowser.Contracts/I18n/TextKey.cs index 8546c53f..180e3fb5 100644 --- a/SafeExamBrowser.Contracts/I18n/TextKey.cs +++ b/SafeExamBrowser.Contracts/I18n/TextKey.cs @@ -44,7 +44,6 @@ namespace SafeExamBrowser.Contracts.I18n SplashScreen_StartEventHandling, SplashScreen_StartKeyboardInterception, SplashScreen_StartMouseInterception, - SplashScreen_StartupProcedure, SplashScreen_StopEventHandling, SplashScreen_StopKeyboardInterception, SplashScreen_StopMouseInterception, diff --git a/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj b/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj index bb6d9e5e..a2abce6c 100644 --- a/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj +++ b/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj @@ -108,6 +108,7 @@ + diff --git a/SafeExamBrowser.Contracts/UserInterface/IProgressIndicator.cs b/SafeExamBrowser.Contracts/UserInterface/IProgressIndicator.cs new file mode 100644 index 00000000..d1fb2880 --- /dev/null +++ b/SafeExamBrowser.Contracts/UserInterface/IProgressIndicator.cs @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2018 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.I18n; + +namespace SafeExamBrowser.Contracts.UserInterface +{ + public interface IProgressIndicator + { + /// + /// Updates the progress value according to the specified amount. + /// + void Progress(int amount = 1); + + /// + /// Regresses the progress value according to the specified amount. + /// + void Regress(int amount = 1); + + /// + /// Sets the style of the progress indicator to indeterminate (Progress and Regress won't have any effect when called). + /// + void SetIndeterminate(); + + /// + /// Sets the maximum progress value. + /// + void SetMaxValue(int max); + + /// + /// Sets the current progress value. + /// + void SetValue(int value); + + /// + /// Updates the status text. If the busy flag is set, an animation will be shown to indicate a long-running operation. + /// + void UpdateText(TextKey key, bool showBusyIndication = false); + } +} diff --git a/SafeExamBrowser.Contracts/UserInterface/IRuntimeWindow.cs b/SafeExamBrowser.Contracts/UserInterface/IRuntimeWindow.cs index eae421e4..e8e0e8b2 100644 --- a/SafeExamBrowser.Contracts/UserInterface/IRuntimeWindow.cs +++ b/SafeExamBrowser.Contracts/UserInterface/IRuntimeWindow.cs @@ -6,17 +6,20 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using SafeExamBrowser.Contracts.I18n; using SafeExamBrowser.Contracts.Logging; namespace SafeExamBrowser.Contracts.UserInterface { - public interface IRuntimeWindow : ILogObserver, IWindow + public interface IRuntimeWindow : ILogObserver, IProgressIndicator, IWindow { /// - /// Updates the status text of the runtime window. If the busy flag is set, - /// the window will show an animation to indicate a long-running operation. + /// Hides the progress bar. /// - void UpdateStatus(TextKey key, bool showBusyIndication = false); + void HideProgressBar(); + + /// + /// Shows the progress bar. + /// + void ShowProgressBar(); } } diff --git a/SafeExamBrowser.Contracts/UserInterface/ISplashScreen.cs b/SafeExamBrowser.Contracts/UserInterface/ISplashScreen.cs index 4b04e592..d6c5a83a 100644 --- a/SafeExamBrowser.Contracts/UserInterface/ISplashScreen.cs +++ b/SafeExamBrowser.Contracts/UserInterface/ISplashScreen.cs @@ -6,37 +6,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using SafeExamBrowser.Contracts.I18n; - namespace SafeExamBrowser.Contracts.UserInterface { - public interface ISplashScreen : IWindow + public interface ISplashScreen : IProgressIndicator, IWindow { - /// - /// 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 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. - /// - void UpdateText(TextKey key, bool showBusyIndication = false); } } diff --git a/SafeExamBrowser.Core.UnitTests/Behaviour/Operations/I18nOperationTests.cs b/SafeExamBrowser.Core.UnitTests/Behaviour/Operations/I18nOperationTests.cs index af612aa8..490ad50d 100644 --- a/SafeExamBrowser.Core.UnitTests/Behaviour/Operations/I18nOperationTests.cs +++ b/SafeExamBrowser.Core.UnitTests/Behaviour/Operations/I18nOperationTests.cs @@ -10,7 +10,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using SafeExamBrowser.Contracts.I18n; using SafeExamBrowser.Contracts.Logging; -using SafeExamBrowser.Contracts.UserInterface; using SafeExamBrowser.Core.Behaviour.Operations; namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations @@ -19,7 +18,6 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations public class I18nOperationTests { private Mock loggerMock; - private Mock splashScreenMock; private Mock textMock; private I18nOperation sut; @@ -28,13 +26,9 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations public void Initialize() { loggerMock = new Mock(); - splashScreenMock = new Mock(); textMock = new Mock(); - sut = new I18nOperation(loggerMock.Object, textMock.Object) - { - SplashScreen = splashScreenMock.Object - }; + sut = new I18nOperation(loggerMock.Object, textMock.Object); } [TestMethod] diff --git a/SafeExamBrowser.Core.UnitTests/Behaviour/Operations/OperationSequenceTests.cs b/SafeExamBrowser.Core.UnitTests/Behaviour/Operations/OperationSequenceTests.cs index 3f7c68bf..2ed608cd 100644 --- a/SafeExamBrowser.Core.UnitTests/Behaviour/Operations/OperationSequenceTests.cs +++ b/SafeExamBrowser.Core.UnitTests/Behaviour/Operations/OperationSequenceTests.cs @@ -11,8 +11,6 @@ using System.Collections.Generic; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using SafeExamBrowser.Contracts.Behaviour.Operations; -using SafeExamBrowser.Contracts.Configuration; -using SafeExamBrowser.Contracts.I18n; using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.UserInterface; using SafeExamBrowser.Core.Behaviour.Operations; @@ -23,28 +21,17 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations public class OperationSequenceTests { private Mock loggerMock; - private Mock runtimeInfoMock; - private Mock textMock; - private Mock uiFactoryMock; - - private IOperationSequence sut; [TestInitialize] public void Initialize() { loggerMock = new Mock(); - runtimeInfoMock = new Mock(); - textMock = new Mock(); - uiFactoryMock = new Mock(); - uiFactoryMock.Setup(f => f.CreateSplashScreen(runtimeInfoMock.Object, textMock.Object)).Returns(new Mock().Object); - - sut = new OperationSequence(loggerMock.Object, runtimeInfoMock.Object, textMock.Object, uiFactoryMock.Object); } #region Perform Tests [TestMethod] - public void MustCorrectlyAbortProcess() + public void MustCorrectlyAbortPerform() { var operationA = new Mock(); var operationB = new Mock(); @@ -57,7 +44,8 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations operations.Enqueue(operationB.Object); operations.Enqueue(operationC.Object); - var success = sut.TryPerform(operations); + var sut = new OperationSequence(loggerMock.Object, operations); + var success = sut.TryPerform(); operationA.Verify(o => o.Perform(), Times.Once); operationA.Verify(o => o.Revert(), Times.Once); @@ -81,7 +69,8 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations operations.Enqueue(operationB.Object); operations.Enqueue(operationC.Object); - var success = sut.TryPerform(operations); + var sut = new OperationSequence(loggerMock.Object, operations); + var success = sut.TryPerform(); operationA.Verify(o => o.Perform(), Times.Once); operationA.Verify(o => o.Revert(), Times.Never); @@ -110,7 +99,8 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations operations.Enqueue(operationB.Object); operations.Enqueue(operationC.Object); - var success = sut.TryPerform(operations); + var sut = new OperationSequence(loggerMock.Object, operations); + var success = sut.TryPerform(); Assert.IsTrue(success); Assert.IsTrue(a == 1); @@ -134,7 +124,8 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations operations.Enqueue(operationC.Object); operations.Enqueue(operationD.Object); - var success = sut.TryPerform(operations); + var sut = new OperationSequence(loggerMock.Object, operations); + var success = sut.TryPerform(); operationA.Verify(o => o.Perform(), Times.Once); operationA.Verify(o => o.Revert(), Times.Once); @@ -169,7 +160,8 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations operations.Enqueue(operationC.Object); operations.Enqueue(operationD.Object); - var success = sut.TryPerform(operations); + var sut = new OperationSequence(loggerMock.Object, operations); + var success = sut.TryPerform(); Assert.IsFalse(success); Assert.IsTrue(d == 0); @@ -195,7 +187,8 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations operations.Enqueue(operationB.Object); operations.Enqueue(operationC.Object); - var result = sut.TryPerform(operations); + var sut = new OperationSequence(loggerMock.Object, operations); + var success = sut.TryPerform(); operationA.Verify(o => o.Perform(), Times.Once); operationA.Verify(o => o.Revert(), Times.Once); @@ -208,18 +201,23 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations [TestMethod] public void MustSucceedWithEmptyQueue() { - var result = sut.TryPerform(new Queue()); + var sut = new OperationSequence(loggerMock.Object, new Queue()); + var success = sut.TryPerform(); - Assert.IsTrue(result); + Assert.IsTrue(success); } [TestMethod] public void MustNotFailInCaseOfUnexpectedError() { - uiFactoryMock.Setup(l => l.CreateSplashScreen(It.IsAny(), It.IsAny())).Throws(new Exception()); + var sut = new OperationSequence(loggerMock.Object, new Queue()); + var indicatorMock = new Mock(); - var success = sut.TryPerform(new Queue()); + indicatorMock.Setup(i => i.SetMaxValue(It.IsAny())).Throws(); + sut.ProgressIndicator = indicatorMock.Object; + + var success = sut.TryPerform(); Assert.IsFalse(success); } @@ -229,10 +227,147 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations #region Repeat Tests [TestMethod] - public void Fail() + public void MustCorrectlyAbortRepeat() { - // TODO - Assert.Fail(); + var operationA = new Mock(); + var operationB = new Mock(); + var operationC = new Mock(); + var operations = new Queue(); + + operationB.SetupGet(o => o.Abort).Returns(true); + + operations.Enqueue(operationA.Object); + operations.Enqueue(operationB.Object); + operations.Enqueue(operationC.Object); + + var sut = new OperationSequence(loggerMock.Object, operations); + var success = sut.TryRepeat(); + + operationA.Verify(o => o.Repeat(), Times.Once); + operationA.Verify(o => o.Revert(), Times.Never); + operationB.Verify(o => o.Repeat(), Times.Once); + operationB.Verify(o => o.Revert(), Times.Never); + operationC.Verify(o => o.Repeat(), Times.Never); + operationC.Verify(o => o.Revert(), Times.Never); + + Assert.IsFalse(success); + } + + [TestMethod] + public void MustRepeatOperations() + { + var operationA = new Mock(); + var operationB = new Mock(); + var operationC = new Mock(); + var operations = new Queue(); + + operations.Enqueue(operationA.Object); + operations.Enqueue(operationB.Object); + operations.Enqueue(operationC.Object); + + var sut = new OperationSequence(loggerMock.Object, operations); + var success = sut.TryRepeat(); + + operationA.Verify(o => o.Perform(), Times.Never); + operationA.Verify(o => o.Repeat(), Times.Once); + operationA.Verify(o => o.Revert(), Times.Never); + operationB.Verify(o => o.Perform(), Times.Never); + operationB.Verify(o => o.Repeat(), Times.Once); + operationB.Verify(o => o.Revert(), Times.Never); + operationC.Verify(o => o.Perform(), Times.Never); + operationC.Verify(o => o.Repeat(), Times.Once); + operationC.Verify(o => o.Revert(), Times.Never); + + Assert.IsTrue(success); + } + + [TestMethod] + public void MustRepeatOperationsInSequence() + { + int current = 0, a = 0, b = 0, c = 0; + var operationA = new Mock(); + var operationB = new Mock(); + var operationC = new Mock(); + var operations = new Queue(); + + operationA.Setup(o => o.Repeat()).Callback(() => a = ++current); + operationB.Setup(o => o.Repeat()).Callback(() => b = ++current); + operationC.Setup(o => o.Repeat()).Callback(() => c = ++current); + + operations.Enqueue(operationA.Object); + operations.Enqueue(operationB.Object); + operations.Enqueue(operationC.Object); + + var sut = new OperationSequence(loggerMock.Object, operations); + var success = sut.TryRepeat(); + + Assert.IsTrue(success); + Assert.IsTrue(a == 1); + Assert.IsTrue(b == 2); + Assert.IsTrue(c == 3); + } + + [TestMethod] + public void MustNotRevertOperationsInCaseOfError() + { + var operationA = new Mock(); + var operationB = new Mock(); + var operationC = new Mock(); + var operationD = new Mock(); + var operations = new Queue(); + + operationC.Setup(o => o.Repeat()).Throws(); + + operations.Enqueue(operationA.Object); + operations.Enqueue(operationB.Object); + operations.Enqueue(operationC.Object); + operations.Enqueue(operationD.Object); + + var sut = new OperationSequence(loggerMock.Object, operations); + var success = sut.TryRepeat(); + + operationA.Verify(o => o.Repeat(), Times.Once); + operationA.Verify(o => o.Revert(), Times.Never); + operationB.Verify(o => o.Repeat(), Times.Once); + operationB.Verify(o => o.Revert(), Times.Never); + operationC.Verify(o => o.Repeat(), Times.Once); + operationC.Verify(o => o.Revert(), Times.Never); + operationD.Verify(o => o.Repeat(), Times.Never); + operationD.Verify(o => o.Revert(), Times.Never); + + Assert.IsFalse(success); + } + + [TestMethod] + public void MustSucceedRepeatingWithEmptyQueue() + { + var sut = new OperationSequence(loggerMock.Object, new Queue()); + var success = sut.TryRepeat(); + + Assert.IsTrue(success); + } + + [TestMethod] + public void MustSucceedRepeatingWithoutCallingPerform() + { + var sut = new OperationSequence(loggerMock.Object, new Queue()); + var success = sut.TryRepeat(); + + Assert.IsTrue(success); + } + + [TestMethod] + public void MustNotFailInCaseOfUnexpectedErrorWhenRepeating() + { + var sut = new OperationSequence(loggerMock.Object, new Queue()); + var indicatorMock = new Mock(); + + indicatorMock.Setup(i => i.SetMaxValue(It.IsAny())).Throws(); + sut.ProgressIndicator = indicatorMock.Object; + + var success = sut.TryRepeat(); + + Assert.IsFalse(success); } #endregion @@ -251,7 +386,9 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations operations.Enqueue(operationB.Object); operations.Enqueue(operationC.Object); - sut.TryPerform(operations); + var sut = new OperationSequence(loggerMock.Object, operations); + + sut.TryPerform(); var success = sut.TryRevert(); @@ -279,7 +416,9 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations operations.Enqueue(operationB.Object); operations.Enqueue(operationC.Object); - sut.TryPerform(operations); + var sut = new OperationSequence(loggerMock.Object, operations); + + sut.TryPerform(); var success = sut.TryRevert(); @@ -305,7 +444,9 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations operations.Enqueue(operationB.Object); operations.Enqueue(operationC.Object); - sut.TryPerform(operations); + var sut = new OperationSequence(loggerMock.Object, operations); + + sut.TryPerform(); var success = sut.TryRevert(); @@ -330,7 +471,9 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations operations.Enqueue(operationB.Object); operations.Enqueue(operationC.Object); - sut.TryPerform(operations); + var sut = new OperationSequence(loggerMock.Object, operations); + + sut.TryPerform(); var success = sut.TryRevert(); @@ -342,15 +485,18 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations } [TestMethod] - public void MustNotFailWithEmptyQueueWhenReverting() + public void MustSucceedWithEmptyQueueWhenReverting() { - sut.TryPerform(new Queue()); + var sut = new OperationSequence(loggerMock.Object, new Queue()); + + sut.TryPerform(); sut.TryRevert(); } [TestMethod] - public void MustNotFailWithoutPerformWhenReverting() + public void MustSucceedRevertingWithoutCallingPerform() { + var sut = new OperationSequence(loggerMock.Object, new Queue()); var success = sut.TryRevert(); Assert.IsTrue(success); @@ -359,8 +505,15 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations [TestMethod] public void MustNotFailInCaseOfUnexpectedErrorWhenReverting() { - uiFactoryMock.Setup(l => l.CreateSplashScreen(It.IsAny(), It.IsAny())).Throws(new Exception()); - sut.TryRevert(); + var sut = new OperationSequence(loggerMock.Object, new Queue()); + var indicatorMock = new Mock(); + + indicatorMock.Setup(i => i.SetMaxValue(It.IsAny())).Throws(); + sut.ProgressIndicator = indicatorMock.Object; + + var success = sut.TryRevert(); + + Assert.IsFalse(success); } #endregion diff --git a/SafeExamBrowser.Core/Behaviour/Operations/I18nOperation.cs b/SafeExamBrowser.Core/Behaviour/Operations/I18nOperation.cs index c702824a..23e86583 100644 --- a/SafeExamBrowser.Core/Behaviour/Operations/I18nOperation.cs +++ b/SafeExamBrowser.Core/Behaviour/Operations/I18nOperation.cs @@ -23,7 +23,7 @@ namespace SafeExamBrowser.Core.Behaviour.Operations private IText text; public bool Abort { get; private set; } - public ISplashScreen SplashScreen { private get; set; } + public IProgressIndicator ProgressIndicator { private get; set; } public I18nOperation(ILogger logger, IText text) { diff --git a/SafeExamBrowser.Core/Behaviour/Operations/OperationSequence.cs b/SafeExamBrowser.Core/Behaviour/Operations/OperationSequence.cs index eefd3ba6..37f4cf92 100644 --- a/SafeExamBrowser.Core/Behaviour/Operations/OperationSequence.cs +++ b/SafeExamBrowser.Core/Behaviour/Operations/OperationSequence.cs @@ -10,8 +10,6 @@ using System; using System.Collections.Generic; using System.Linq; using SafeExamBrowser.Contracts.Behaviour.Operations; -using SafeExamBrowser.Contracts.Configuration; -using SafeExamBrowser.Contracts.I18n; using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.UserInterface; @@ -20,42 +18,34 @@ namespace SafeExamBrowser.Core.Behaviour.Operations public class OperationSequence : IOperationSequence { private ILogger logger; - private IRuntimeInfo runtimeInfo; - private ISplashScreen splashScreen; - private IText text; - private IUserInterfaceFactory uiFactory; - + private Queue operations = new Queue(); private Stack stack = new Stack(); - public OperationSequence(ILogger logger, IRuntimeInfo runtimeInfo, IText text, IUserInterfaceFactory uiFactory) + public IProgressIndicator ProgressIndicator { private get; set; } + + public OperationSequence(ILogger logger, Queue operations) { this.logger = logger; - this.runtimeInfo = runtimeInfo; - this.text = text; - this.uiFactory = uiFactory; + this.operations = new Queue(operations); } - public bool TryPerform(Queue operations) + public bool TryPerform() { var success = false; try { - Initialize(operations.Count); - success = Perform(operations); + Initialize(); + success = Perform(); if (!success) { - RevertOperations(); + Revert(); } } catch (Exception e) { - logger.Error($"Failed to perform operations!", e); - } - finally - { - Finish(); + logger.Error("Failed to perform operations!", e); } return success; @@ -63,7 +53,19 @@ namespace SafeExamBrowser.Core.Behaviour.Operations public bool TryRepeat() { - throw new NotImplementedException(); + var success = false; + + try + { + Initialize(); + success = Repeat(); + } + catch (Exception e) + { + logger.Error("Failed to repeat operations!", e); + } + + return success; } public bool TryRevert() @@ -73,46 +75,38 @@ namespace SafeExamBrowser.Core.Behaviour.Operations try { Initialize(); - success = RevertOperations(false); + success = Revert(false); } catch (Exception e) { - logger.Error($"Failed to revert operations!", e); - } - finally - { - Finish(); + logger.Error("Failed to revert operations!", e); } return success; } - private void Initialize(int? operationCount = null) + private void Initialize(bool indeterminate = false) { - splashScreen = uiFactory.CreateSplashScreen(runtimeInfo, text); - - if (operationCount.HasValue) + if (indeterminate) { - splashScreen.SetMaxProgress(operationCount.Value); + ProgressIndicator?.SetIndeterminate(); } else { - splashScreen.SetIndeterminate(); + ProgressIndicator?.SetValue(0); + ProgressIndicator?.SetMaxValue(operations.Count); } - - splashScreen.UpdateText(TextKey.SplashScreen_StartupProcedure); - splashScreen.Show(); } - private bool Perform(Queue operations) + private bool Perform() { foreach (var operation in operations) { stack.Push(operation); - operation.SplashScreen = splashScreen; try { + operation.ProgressIndicator = ProgressIndicator; operation.Perform(); } catch (Exception e) @@ -127,13 +121,40 @@ namespace SafeExamBrowser.Core.Behaviour.Operations return false; } - splashScreen.Progress(); + ProgressIndicator?.Progress(); } return true; } - private bool RevertOperations(bool regress = true) + private bool Repeat() + { + foreach (var operation in operations) + { + try + { + operation.ProgressIndicator = ProgressIndicator; + operation.Repeat(); + } + catch (Exception e) + { + logger.Error($"Failed to repeat operation '{operation.GetType().Name}'!", e); + + return false; + } + + if (operation.Abort) + { + return false; + } + + ProgressIndicator?.Progress(); + } + + return true; + } + + private bool Revert(bool regress = true) { var success = true; @@ -143,6 +164,7 @@ namespace SafeExamBrowser.Core.Behaviour.Operations try { + operation.ProgressIndicator = ProgressIndicator; operation.Revert(); } catch (Exception e) @@ -153,16 +175,11 @@ namespace SafeExamBrowser.Core.Behaviour.Operations if (regress) { - splashScreen.Regress(); + ProgressIndicator?.Regress(); } } return success; } - - private void Finish() - { - splashScreen?.Close(); - } } } diff --git a/SafeExamBrowser.Core/I18n/Text.xml b/SafeExamBrowser.Core/I18n/Text.xml index 5755e73a..165de884 100644 --- a/SafeExamBrowser.Core/I18n/Text.xml +++ b/SafeExamBrowser.Core/I18n/Text.xml @@ -87,9 +87,6 @@ Starting mouse interception - - Initiating startup procedure - Stopping event handling diff --git a/SafeExamBrowser.Runtime.UnitTests/Behaviour/Operations/ConfigurationOperationTests.cs b/SafeExamBrowser.Runtime.UnitTests/Behaviour/Operations/ConfigurationOperationTests.cs index ec118d33..8b672df7 100644 --- a/SafeExamBrowser.Runtime.UnitTests/Behaviour/Operations/ConfigurationOperationTests.cs +++ b/SafeExamBrowser.Runtime.UnitTests/Behaviour/Operations/ConfigurationOperationTests.cs @@ -26,7 +26,6 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations private Mock info; private Mock repository; private Mock settings; - private Mock splashScreen; private Mock text; private Mock uiFactory; private ConfigurationOperation sut; @@ -38,7 +37,6 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations info = new Mock(); repository = new Mock(); settings = new Mock(); - splashScreen = new Mock(); text = new Mock(); uiFactory = new Mock(); @@ -54,17 +52,11 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations { repository.Setup(r => r.LoadDefaults()); - sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null) - { - SplashScreen = splashScreen.Object - }; + sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null); sut.Perform(); - sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, new string[] { }) - { - SplashScreen = splashScreen.Object - }; + sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, new string[] { }); sut.Perform(); @@ -76,10 +68,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations { var path = @"an/invalid\path.'*%yolo/()"; - sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, new [] { "blubb.exe", path }) - { - SplashScreen = splashScreen.Object - }; + sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, new [] { "blubb.exe", path }); sut.Perform(); } @@ -93,10 +82,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations info.SetupGet(r => r.ProgramDataFolder).Returns(location); info.SetupGet(r => r.AppDataFolder).Returns(location); - sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, new[] { "blubb.exe", path }) - { - SplashScreen = splashScreen.Object - }; + sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, new[] { "blubb.exe", path }); sut.Perform(); @@ -111,10 +97,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations info.SetupGet(r => r.ProgramDataFolder).Returns(location); info.SetupGet(r => r.AppDataFolder).Returns($@"{location}\WRONG"); - sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null) - { - SplashScreen = splashScreen.Object - }; + sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null); sut.Perform(); @@ -128,10 +111,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations info.SetupGet(r => r.AppDataFolder).Returns(location); - sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null) - { - SplashScreen = splashScreen.Object - }; + sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null); sut.Perform(); @@ -141,10 +121,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations [TestMethod] public void MustFallbackToDefaultsAsLastPrio() { - sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null) - { - SplashScreen = splashScreen.Object - }; + sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null); sut.Perform(); @@ -159,10 +136,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations info.SetupGet(r => r.ProgramDataFolder).Returns(location); uiFactory.Setup(u => u.Show(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(MessageBoxResult.Yes); - sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null) - { - SplashScreen = splashScreen.Object - }; + sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null); sut.Perform(); @@ -174,10 +148,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations { uiFactory.Setup(u => u.Show(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(MessageBoxResult.No); - sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null) - { - SplashScreen = splashScreen.Object - }; + sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null); sut.Perform(); diff --git a/SafeExamBrowser.Runtime.UnitTests/Behaviour/Operations/ServiceOperationTests.cs b/SafeExamBrowser.Runtime.UnitTests/Behaviour/Operations/ServiceOperationTests.cs index 1c5ef75a..6b1e918a 100644 --- a/SafeExamBrowser.Runtime.UnitTests/Behaviour/Operations/ServiceOperationTests.cs +++ b/SafeExamBrowser.Runtime.UnitTests/Behaviour/Operations/ServiceOperationTests.cs @@ -24,7 +24,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations private Mock logger; private Mock service; private Mock settings; - private Mock splashScreen; + private Mock progressIndicator; private Mock text; private ServiceOperation sut; @@ -34,13 +34,10 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations logger = new Mock(); service = new Mock(); settings = new Mock(); - splashScreen = new Mock(); + progressIndicator = new Mock(); text = new Mock(); - sut = new ServiceOperation(logger.Object, service.Object, settings.Object, text.Object) - { - SplashScreen = splashScreen.Object - }; + sut = new ServiceOperation(logger.Object, service.Object, settings.Object, text.Object); } [TestMethod] diff --git a/SafeExamBrowser.Runtime/App.cs b/SafeExamBrowser.Runtime/App.cs index 297b5f4f..ddcf980f 100644 --- a/SafeExamBrowser.Runtime/App.cs +++ b/SafeExamBrowser.Runtime/App.cs @@ -60,7 +60,7 @@ namespace SafeExamBrowser.Runtime instances.BuildObjectGraph(); instances.LogStartupInformation(); - var success = instances.RuntimeController.TryStart(instances.StartupOperations); + var success = instances.RuntimeController.TryStart(); if (!success) { diff --git a/SafeExamBrowser.Runtime/Behaviour/Operations/ConfigurationOperation.cs b/SafeExamBrowser.Runtime/Behaviour/Operations/ConfigurationOperation.cs index cb0922a1..7797e8aa 100644 --- a/SafeExamBrowser.Runtime/Behaviour/Operations/ConfigurationOperation.cs +++ b/SafeExamBrowser.Runtime/Behaviour/Operations/ConfigurationOperation.cs @@ -27,7 +27,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations private string[] commandLineArgs; public bool Abort { get; private set; } - public ISplashScreen SplashScreen { private get; set; } + public IProgressIndicator ProgressIndicator { private get; set; } public ConfigurationOperation( ILogger logger, @@ -48,7 +48,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations public void Perform() { logger.Info("Initializing application configuration..."); - SplashScreen.UpdateText(TextKey.SplashScreen_InitializeConfiguration); + ProgressIndicator?.UpdateText(TextKey.SplashScreen_InitializeConfiguration); ISettings settings; var isValidUri = TryGetSettingsUri(out Uri uri); @@ -73,7 +73,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations public void Repeat() { - // TODO + // TODO: How will the new settings be retrieved? Uri passed to the repository? If yes, how does the Uri get here?! } public void Revert() diff --git a/SafeExamBrowser.Runtime/Behaviour/Operations/KioskModeOperation.cs b/SafeExamBrowser.Runtime/Behaviour/Operations/KioskModeOperation.cs index 65e4739f..5874ee8e 100644 --- a/SafeExamBrowser.Runtime/Behaviour/Operations/KioskModeOperation.cs +++ b/SafeExamBrowser.Runtime/Behaviour/Operations/KioskModeOperation.cs @@ -21,7 +21,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations private KioskMode kioskMode; public bool Abort { get; private set; } - public ISplashScreen SplashScreen { private get; set; } + public IProgressIndicator ProgressIndicator { private get; set; } public KioskModeOperation(ILogger logger, ISettingsRepository settingsRepository) { @@ -34,7 +34,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations kioskMode = settingsRepository.Current.KioskMode; logger.Info($"Initializing kiosk mode '{kioskMode}'..."); - SplashScreen.UpdateText(TextKey.SplashScreen_InitializeKioskMode); + ProgressIndicator?.UpdateText(TextKey.SplashScreen_InitializeKioskMode); if (kioskMode == KioskMode.CreateNewDesktop) { @@ -54,7 +54,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations public void Revert() { logger.Info($"Reverting kiosk mode '{kioskMode}'..."); - SplashScreen.UpdateText(TextKey.SplashScreen_RevertKioskMode); + ProgressIndicator?.UpdateText(TextKey.SplashScreen_RevertKioskMode); if (kioskMode == KioskMode.CreateNewDesktop) { diff --git a/SafeExamBrowser.Runtime/Behaviour/Operations/ServiceOperation.cs b/SafeExamBrowser.Runtime/Behaviour/Operations/ServiceOperation.cs index a1573080..a49a42dd 100644 --- a/SafeExamBrowser.Runtime/Behaviour/Operations/ServiceOperation.cs +++ b/SafeExamBrowser.Runtime/Behaviour/Operations/ServiceOperation.cs @@ -26,7 +26,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations private IText text; public bool Abort { get; private set; } - public ISplashScreen SplashScreen { private get; set; } + public IProgressIndicator ProgressIndicator { private get; set; } public ServiceOperation(ILogger logger, IServiceProxy service, ISettingsRepository settingsRepository, IText text) { @@ -39,7 +39,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations public void Perform() { logger.Info($"Initializing service connection..."); - SplashScreen.UpdateText(TextKey.SplashScreen_InitializeServiceConnection); + ProgressIndicator?.UpdateText(TextKey.SplashScreen_InitializeServiceConnection); try { @@ -71,7 +71,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations public void Revert() { logger.Info("Closing service connection..."); - SplashScreen.UpdateText(TextKey.SplashScreen_CloseServiceConnection); + ProgressIndicator?.UpdateText(TextKey.SplashScreen_CloseServiceConnection); if (serviceAvailable) { diff --git a/SafeExamBrowser.Runtime/Behaviour/RuntimeController.cs b/SafeExamBrowser.Runtime/Behaviour/RuntimeController.cs index e3e14c5f..d7335342 100644 --- a/SafeExamBrowser.Runtime/Behaviour/RuntimeController.cs +++ b/SafeExamBrowser.Runtime/Behaviour/RuntimeController.cs @@ -7,7 +7,6 @@ */ using System; -using System.Collections.Generic; using SafeExamBrowser.Contracts.Behaviour; using SafeExamBrowser.Contracts.Behaviour.Operations; using SafeExamBrowser.Contracts.Communication; @@ -22,18 +21,21 @@ namespace SafeExamBrowser.Runtime.Behaviour internal class RuntimeController : IRuntimeController { private ILogger logger; + private IOperationSequence bootstrapSequence; + private IOperationSequence sessionSequence; private IRuntimeInfo runtimeInfo; private IRuntimeWindow runtimeWindow; private IServiceProxy serviceProxy; private ISettingsRepository settingsRepository; - private IOperationSequence operationSequence; + private ISplashScreen splashScreen; private Action terminationCallback; private IText text; private IUserInterfaceFactory uiFactory; public RuntimeController( ILogger logger, - IOperationSequence operationSequence, + IOperationSequence bootstrapSequence, + IOperationSequence sessionSequence, IRuntimeInfo runtimeInfo, IServiceProxy serviceProxy, ISettingsRepository settingsRepository, @@ -42,7 +44,8 @@ namespace SafeExamBrowser.Runtime.Behaviour IUserInterfaceFactory uiFactory) { this.logger = logger; - this.operationSequence = operationSequence; + this.bootstrapSequence = bootstrapSequence; + this.sessionSequence = sessionSequence; this.runtimeInfo = runtimeInfo; this.serviceProxy = serviceProxy; this.settingsRepository = settingsRepository; @@ -51,21 +54,30 @@ namespace SafeExamBrowser.Runtime.Behaviour this.uiFactory = uiFactory; } - public bool TryStart(Queue operations) + public bool TryStart() { logger.Info("--- Initiating startup procedure ---"); - var success = operationSequence.TryPerform(operations); + splashScreen = uiFactory.CreateSplashScreen(runtimeInfo, text); + splashScreen.Show(); - runtimeWindow = uiFactory.CreateRuntimeWindow(runtimeInfo, text); + bootstrapSequence.ProgressIndicator = splashScreen; + + var success = bootstrapSequence.TryPerform(); + + System.Threading.Thread.Sleep(5000); if (success) { + runtimeWindow = uiFactory.CreateRuntimeWindow(runtimeInfo, text); + logger.Info("--- Application successfully initialized! ---"); logger.Log(string.Empty); logger.Subscribe(runtimeWindow); - StartSession(); + splashScreen.Hide(); + + StartSession(true); } else { @@ -76,33 +88,6 @@ namespace SafeExamBrowser.Runtime.Behaviour return success; } - public void StartSession() - { - runtimeWindow.Show(); - - logger.Info("Starting new session..."); - runtimeWindow.UpdateStatus(TextKey.RuntimeWindow_StartSession, true); - - // TODO: - // - Initialize configuration - // - Initialize kiosk mode - // - Initialize session data - // - Start runtime communication host - // - Create and connect to client - // - Initialize session with service - // - Verify session integrity and start event handling - System.Threading.Thread.Sleep(10000); - - runtimeWindow.UpdateStatus(TextKey.RuntimeWindow_ApplicationRunning); - - if (settingsRepository.Current.KioskMode == KioskMode.DisableExplorerShell) - { - runtimeWindow.Hide(); - } - - terminationCallback.Invoke(); - } - public void Terminate() { StopSession(); @@ -113,12 +98,13 @@ namespace SafeExamBrowser.Runtime.Behaviour // - Revert kiosk mode (or do that when stopping session?) logger.Unsubscribe(runtimeWindow); - runtimeWindow.Close(); + runtimeWindow?.Close(); + splashScreen?.Show(); logger.Log(string.Empty); logger.Info("--- Initiating shutdown procedure ---"); - var success = operationSequence.TryRevert(); + var success = bootstrapSequence.TryRevert(); if (success) { @@ -128,6 +114,48 @@ namespace SafeExamBrowser.Runtime.Behaviour { logger.Info("--- Shutdown procedure failed! ---"); } + + splashScreen?.Close(); + } + + private void StartSession(bool initial = false) + { + logger.Info("Starting new session..."); + runtimeWindow.UpdateText(TextKey.RuntimeWindow_StartSession, true); + runtimeWindow.Show(); + + sessionSequence.ProgressIndicator = runtimeWindow; + + // TODO: + // - Initialize configuration + // - Initialize kiosk mode + // - Initialize session data + // - Create and connect to client + // - Initialize session with service + // - Verify session integrity and start event handling + var success = initial ? sessionSequence.TryPerform() : sessionSequence.TryRepeat(); + + if (success) + { + + } + else + { + + } + + System.Threading.Thread.Sleep(5000); + + runtimeWindow.UpdateText(TextKey.RuntimeWindow_ApplicationRunning); + + if (settingsRepository.Current.KioskMode == KioskMode.DisableExplorerShell) + { + runtimeWindow.Hide(); + } + + System.Threading.Thread.Sleep(5000); + + terminationCallback.Invoke(); } private void StopSession() @@ -135,7 +163,7 @@ namespace SafeExamBrowser.Runtime.Behaviour logger.Info("Stopping current session..."); runtimeWindow.Show(); runtimeWindow.BringToForeground(); - runtimeWindow.UpdateStatus(TextKey.RuntimeWindow_StopSession, true); + runtimeWindow.UpdateText(TextKey.RuntimeWindow_StopSession, true); // TODO: // - Terminate client (or does it terminate itself?) diff --git a/SafeExamBrowser.Runtime/CompositionRoot.cs b/SafeExamBrowser.Runtime/CompositionRoot.cs index 36526141..bca23e0b 100644 --- a/SafeExamBrowser.Runtime/CompositionRoot.cs +++ b/SafeExamBrowser.Runtime/CompositionRoot.cs @@ -35,11 +35,12 @@ namespace SafeExamBrowser.Runtime private ISystemInfo systemInfo; internal IRuntimeController RuntimeController { get; private set; } - internal Queue StartupOperations { get; private set; } internal void BuildObjectGraph() { var args = Environment.GetCommandLineArgs(); + var bootstrapOperations = new Queue(); + var sessionOperations = new Queue(); var nativeMethods = new NativeMethods(); var settingsRepository = new SettingsRepository(); var uiFactory = new UserInterfaceFactory(); @@ -52,16 +53,19 @@ namespace SafeExamBrowser.Runtime InitializeLogging(); var text = new Text(logger); - var operationSequence = new OperationSequence(logger, runtimeInfo, text, uiFactory); var serviceProxy = new ServiceProxy(new ModuleLogger(logger, typeof(ServiceProxy)), "net.pipe://localhost/safeexambrowser/service"); - RuntimeController = new RuntimeController(logger, operationSequence, runtimeInfo, serviceProxy, settingsRepository, Application.Current.Shutdown, text, uiFactory); + bootstrapOperations.Enqueue(new I18nOperation(logger, text)); + // TODO: RuntimeHostOperation here (is IBootstrapOperation -> only performed once per runtime!) - StartupOperations = new Queue(); - StartupOperations.Enqueue(new I18nOperation(logger, text)); - StartupOperations.Enqueue(new ConfigurationOperation(logger, runtimeInfo, settingsRepository, text, uiFactory, args)); - StartupOperations.Enqueue(new ServiceOperation(logger, serviceProxy, settingsRepository, text)); - StartupOperations.Enqueue(new KioskModeOperation(logger, settingsRepository)); + sessionOperations.Enqueue(new ConfigurationOperation(logger, runtimeInfo, settingsRepository, text, uiFactory, args)); + sessionOperations.Enqueue(new ServiceOperation(logger, serviceProxy, settingsRepository, text)); + sessionOperations.Enqueue(new KioskModeOperation(logger, settingsRepository)); + + var bootstrapSequence = new OperationSequence(logger, bootstrapOperations); + var sessionSequence = new OperationSequence(logger, sessionOperations); + + RuntimeController = new RuntimeController(logger, bootstrapSequence, sessionSequence, runtimeInfo, serviceProxy, settingsRepository, Application.Current.Shutdown, text, uiFactory); } internal void LogStartupInformation() diff --git a/SafeExamBrowser.UserInterface.Classic/RuntimeWindow.xaml b/SafeExamBrowser.UserInterface.Classic/RuntimeWindow.xaml index e443bf17..78bef994 100644 --- a/SafeExamBrowser.UserInterface.Classic/RuntimeWindow.xaml +++ b/SafeExamBrowser.UserInterface.Classic/RuntimeWindow.xaml @@ -8,7 +8,7 @@ mc:Ignorable="d" Background="White" Foreground="White" Height="500" Width="750" WindowStyle="None" WindowStartupLocation="CenterScreen" Icon="./Images/SafeExamBrowser.ico" ResizeMode="NoResize" Title="Safe Exam Browser" Topmost="True"> - + @@ -41,8 +41,11 @@ - - + + diff --git a/SafeExamBrowser.UserInterface.Classic/RuntimeWindow.xaml.cs b/SafeExamBrowser.UserInterface.Classic/RuntimeWindow.xaml.cs index f2f25a1a..dbad843a 100644 --- a/SafeExamBrowser.UserInterface.Classic/RuntimeWindow.xaml.cs +++ b/SafeExamBrowser.UserInterface.Classic/RuntimeWindow.xaml.cs @@ -9,7 +9,6 @@ using System; using System.Windows; using System.Windows.Documents; -using System.Windows.Input; using SafeExamBrowser.Contracts.Configuration; using SafeExamBrowser.Contracts.I18n; using SafeExamBrowser.Contracts.Logging; @@ -62,6 +61,11 @@ namespace SafeExamBrowser.UserInterface.Classic Dispatcher.Invoke(base.Hide); } + public void HideProgressBar() + { + model.ProgressBarVisibility = Visibility.Hidden; + } + public void Notify(ILogContent content) { Dispatcher.Invoke(() => @@ -71,28 +75,52 @@ namespace SafeExamBrowser.UserInterface.Classic }); } + 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 SetMaxValue(int max) + { + model.MaxProgress = max; + } + + public void SetValue(int value) + { + model.CurrentProgress = value; + } + + public void ShowProgressBar() + { + model.ProgressBarVisibility = Visibility.Visible; + } + + public void UpdateText(TextKey key, bool showBusyIndication = false) + { + model.StopBusyIndication(); + model.Status = text.Get(key); + + if (showBusyIndication) + { + model.StartBusyIndication(); + } + } + public new void Show() { Dispatcher.Invoke(base.Show); } - public void UpdateStatus(TextKey key, bool showBusyIndication = false) - { - Dispatcher.Invoke(() => - { - AnimatedBorder.Visibility = showBusyIndication ? Visibility.Hidden : Visibility.Visible; - ProgressBar.Visibility = showBusyIndication ? Visibility.Visible : Visibility.Hidden; - - model.StopBusyIndication(); - model.Status = text.Get(key); - - if (showBusyIndication) - { - model.StartBusyIndication(); - } - }); - } - private void InitializeRuntimeWindow() { Title = $"{runtimeInfo.ProgramTitle} - Version {runtimeInfo.ProgramVersion}"; @@ -103,6 +131,8 @@ namespace SafeExamBrowser.UserInterface.Classic InfoTextBlock.Inlines.Add(new Run(runtimeInfo.ProgramCopyright) { FontSize = 10 }); model = new RuntimeWindowViewModel(); + AnimatedBorder.DataContext = model; + ProgressBar.DataContext = model; StatusTextBlock.DataContext = model; Closing += (o, args) => args.Cancel = !allowClose; diff --git a/SafeExamBrowser.UserInterface.Classic/SafeExamBrowser.UserInterface.Classic.csproj b/SafeExamBrowser.UserInterface.Classic/SafeExamBrowser.UserInterface.Classic.csproj index 2d493715..677b263b 100644 --- a/SafeExamBrowser.UserInterface.Classic/SafeExamBrowser.UserInterface.Classic.csproj +++ b/SafeExamBrowser.UserInterface.Classic/SafeExamBrowser.UserInterface.Classic.csproj @@ -118,8 +118,8 @@ + - Designer MSBuild:Compile diff --git a/SafeExamBrowser.UserInterface.Classic/SplashScreen.xaml.cs b/SafeExamBrowser.UserInterface.Classic/SplashScreen.xaml.cs index ab135041..78d7c884 100644 --- a/SafeExamBrowser.UserInterface.Classic/SplashScreen.xaml.cs +++ b/SafeExamBrowser.UserInterface.Classic/SplashScreen.xaml.cs @@ -18,7 +18,7 @@ namespace SafeExamBrowser.UserInterface.Classic public partial class SplashScreen : Window, ISplashScreen { private bool allowClose; - private SplashScreenViewModel model = new SplashScreenViewModel(); + private ProgressIndicatorViewModel model = new ProgressIndicatorViewModel(); private IRuntimeInfo runtimeInfo; private IText text; private WindowClosingEventHandler closing; @@ -77,11 +77,16 @@ namespace SafeExamBrowser.UserInterface.Classic model.IsIndeterminate = true; } - public void SetMaxProgress(int max) + public void SetMaxValue(int max) { model.MaxProgress = max; } + public void SetValue(int value) + { + model.CurrentProgress = value; + } + public void UpdateText(TextKey key, bool showBusyIndication = false) { model.StopBusyIndication(); diff --git a/SafeExamBrowser.UserInterface.Classic/ViewModels/SplashScreenViewModel.cs b/SafeExamBrowser.UserInterface.Classic/ViewModels/ProgressIndicatorViewModel.cs similarity index 86% rename from SafeExamBrowser.UserInterface.Classic/ViewModels/SplashScreenViewModel.cs rename to SafeExamBrowser.UserInterface.Classic/ViewModels/ProgressIndicatorViewModel.cs index 1b71eb11..ce0b1259 100644 --- a/SafeExamBrowser.UserInterface.Classic/ViewModels/SplashScreenViewModel.cs +++ b/SafeExamBrowser.UserInterface.Classic/ViewModels/ProgressIndicatorViewModel.cs @@ -11,7 +11,7 @@ using System.Timers; namespace SafeExamBrowser.UserInterface.Classic.ViewModels { - class SplashScreenViewModel : INotifyPropertyChanged + internal class ProgressIndicatorViewModel : INotifyPropertyChanged { private int currentProgress; private bool isIndeterminate; @@ -73,7 +73,7 @@ namespace SafeExamBrowser.UserInterface.Classic.ViewModels } } - public void StartBusyIndication() + public virtual void StartBusyIndication() { StopBusyIndication(); @@ -87,12 +87,17 @@ namespace SafeExamBrowser.UserInterface.Classic.ViewModels busyTimer.Start(); } - public void StopBusyIndication() + public virtual void StopBusyIndication() { busyTimer?.Stop(); busyTimer?.Close(); } + protected void OnPropertyChanged(string propertyName) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + private void BusyTimer_Elapsed(object sender, ElapsedEventArgs e) { var next = Status ?? string.Empty; diff --git a/SafeExamBrowser.UserInterface.Classic/ViewModels/RuntimeWindowViewModel.cs b/SafeExamBrowser.UserInterface.Classic/ViewModels/RuntimeWindowViewModel.cs index 7c411cba..6c5bd6e2 100644 --- a/SafeExamBrowser.UserInterface.Classic/ViewModels/RuntimeWindowViewModel.cs +++ b/SafeExamBrowser.UserInterface.Classic/ViewModels/RuntimeWindowViewModel.cs @@ -6,65 +6,52 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using System.ComponentModel; -using System.Timers; +using System.Windows; namespace SafeExamBrowser.UserInterface.Classic.ViewModels { - internal class RuntimeWindowViewModel : INotifyPropertyChanged + internal class RuntimeWindowViewModel : ProgressIndicatorViewModel { - private string status; - private Timer timer; + private Visibility animatedBorderVisibility, progressBarVisibility; - public event PropertyChangedEventHandler PropertyChanged; - - public string Status + public Visibility AnimatedBorderVisibility { get { - return status; + return animatedBorderVisibility; } set { - status = value; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Status))); + animatedBorderVisibility = value; + OnPropertyChanged(nameof(AnimatedBorderVisibility)); } } - public void StartBusyIndication() + public Visibility ProgressBarVisibility { - StopBusyIndication(); - - timer = new Timer + get { - AutoReset = true, - Interval = 750 - }; - - timer.Elapsed += Timer_Elapsed; - timer.Start(); + return progressBarVisibility; + } + set + { + progressBarVisibility = value; + OnPropertyChanged(nameof(ProgressBarVisibility)); + } } - public void StopBusyIndication() + public override void StartBusyIndication() { - timer?.Stop(); - timer?.Close(); + base.StartBusyIndication(); + + AnimatedBorderVisibility = Visibility.Hidden; } - private void Timer_Elapsed(object sender, ElapsedEventArgs e) + public override void StopBusyIndication() { - var next = Status ?? string.Empty; + base.StopBusyIndication(); - if (next.EndsWith("...")) - { - next = Status.Substring(0, Status.Length - 3); - } - else - { - next += "."; - } - - Status = next; + AnimatedBorderVisibility = Visibility.Visible; } } } diff --git a/SafeExamBrowser.UserInterface.Windows10/SplashScreen.xaml.cs b/SafeExamBrowser.UserInterface.Windows10/SplashScreen.xaml.cs index 59bff6df..eaae84c1 100644 --- a/SafeExamBrowser.UserInterface.Windows10/SplashScreen.xaml.cs +++ b/SafeExamBrowser.UserInterface.Windows10/SplashScreen.xaml.cs @@ -77,11 +77,16 @@ namespace SafeExamBrowser.UserInterface.Windows10 model.IsIndeterminate = true; } - public void SetMaxProgress(int max) + public void SetMaxValue(int max) { model.MaxProgress = max; } + public void SetValue(int value) + { + model.CurrentProgress = value; + } + public void UpdateText(TextKey key, bool showBusyIndication = false) { model.StopBusyIndication();