SEBWIN-219: Finally found appropriate solution for handling bootstrap- and session-operations.

This commit is contained in:
dbuechel 2018-02-02 09:18:35 +01:00
parent 196836b7eb
commit 5b57734406
46 changed files with 559 additions and 393 deletions

View file

@ -23,7 +23,6 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations
private Mock<IApplicationController> controllerMock; private Mock<IApplicationController> controllerMock;
private Mock<IApplicationInfo> appInfoMock; private Mock<IApplicationInfo> appInfoMock;
private Mock<ILogger> loggerMock; private Mock<ILogger> loggerMock;
private Mock<ISplashScreen> splashScreenMock;
private Mock<ITaskbar> taskbarMock; private Mock<ITaskbar> taskbarMock;
private Mock<IUserInterfaceFactory> uiFactoryMock; private Mock<IUserInterfaceFactory> uiFactoryMock;
@ -35,14 +34,10 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations
controllerMock = new Mock<IApplicationController>(); controllerMock = new Mock<IApplicationController>();
appInfoMock = new Mock<IApplicationInfo>(); appInfoMock = new Mock<IApplicationInfo>();
loggerMock = new Mock<ILogger>(); loggerMock = new Mock<ILogger>();
splashScreenMock = new Mock<ISplashScreen>();
taskbarMock = new Mock<ITaskbar>(); taskbarMock = new Mock<ITaskbar>();
uiFactoryMock = new Mock<IUserInterfaceFactory>(); uiFactoryMock = new Mock<IUserInterfaceFactory>();
sut = new BrowserOperation(controllerMock.Object, appInfoMock.Object, loggerMock.Object, taskbarMock.Object, uiFactoryMock.Object) sut = new BrowserOperation(controllerMock.Object, appInfoMock.Object, loggerMock.Object, taskbarMock.Object, uiFactoryMock.Object);
{
SplashScreen = splashScreenMock.Object
};
} }
[TestMethod] [TestMethod]

View file

@ -11,7 +11,6 @@ using Moq;
using SafeExamBrowser.Client.Behaviour.Operations; using SafeExamBrowser.Client.Behaviour.Operations;
using SafeExamBrowser.Contracts.Behaviour; using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.UserInterface;
namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations
{ {
@ -20,7 +19,6 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations
{ {
private Mock<ILogger> loggerMock; private Mock<ILogger> loggerMock;
private Mock<IClientController> clientControllerMock; private Mock<IClientController> clientControllerMock;
private Mock<ISplashScreen> splashScreenMock;
private ClientControllerOperation sut; private ClientControllerOperation sut;
@ -29,12 +27,8 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations
{ {
loggerMock = new Mock<ILogger>(); loggerMock = new Mock<ILogger>();
clientControllerMock = new Mock<IClientController>(); clientControllerMock = new Mock<IClientController>();
splashScreenMock = new Mock<ISplashScreen>();
sut = new ClientControllerOperation(clientControllerMock.Object, loggerMock.Object) sut = new ClientControllerOperation(clientControllerMock.Object, loggerMock.Object);
{
SplashScreen = splashScreenMock.Object
};
} }
[TestMethod] [TestMethod]

View file

@ -10,7 +10,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq; using Moq;
using SafeExamBrowser.Client.Behaviour.Operations; using SafeExamBrowser.Client.Behaviour.Operations;
using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.UserInterface;
using SafeExamBrowser.Contracts.WindowsApi; using SafeExamBrowser.Contracts.WindowsApi;
namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations
@ -20,7 +19,6 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations
{ {
private Mock<ILogger> loggerMock; private Mock<ILogger> loggerMock;
private Mock<INativeMethods> nativeMethodsMock; private Mock<INativeMethods> nativeMethodsMock;
private Mock<ISplashScreen> splashScreenMock;
private ClipboardOperation sut; private ClipboardOperation sut;
@ -29,12 +27,8 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations
{ {
loggerMock = new Mock<ILogger>(); loggerMock = new Mock<ILogger>();
nativeMethodsMock = new Mock<INativeMethods>(); nativeMethodsMock = new Mock<INativeMethods>();
splashScreenMock = new Mock<ISplashScreen>();
sut = new ClipboardOperation(loggerMock.Object, nativeMethodsMock.Object) sut = new ClipboardOperation(loggerMock.Object, nativeMethodsMock.Object);
{
SplashScreen = splashScreenMock.Object
};
} }
[TestMethod] [TestMethod]

View file

@ -11,7 +11,6 @@ using Moq;
using SafeExamBrowser.Client.Behaviour.Operations; using SafeExamBrowser.Client.Behaviour.Operations;
using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.Monitoring; using SafeExamBrowser.Contracts.Monitoring;
using SafeExamBrowser.Contracts.UserInterface;
using SafeExamBrowser.Contracts.UserInterface.Taskbar; using SafeExamBrowser.Contracts.UserInterface.Taskbar;
namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations
@ -21,7 +20,6 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations
{ {
private Mock<IDisplayMonitor> displayMonitorMock; private Mock<IDisplayMonitor> displayMonitorMock;
private Mock<ILogger> loggerMock; private Mock<ILogger> loggerMock;
private Mock<ISplashScreen> splashScreenMock;
private Mock<ITaskbar> taskbarMock; private Mock<ITaskbar> taskbarMock;
private DisplayMonitorOperation sut; private DisplayMonitorOperation sut;
@ -31,13 +29,9 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations
{ {
loggerMock = new Mock<ILogger>(); loggerMock = new Mock<ILogger>();
displayMonitorMock = new Mock<IDisplayMonitor>(); displayMonitorMock = new Mock<IDisplayMonitor>();
splashScreenMock = new Mock<ISplashScreen>();
taskbarMock = new Mock<ITaskbar>(); taskbarMock = new Mock<ITaskbar>();
sut = new DisplayMonitorOperation(displayMonitorMock.Object, loggerMock.Object, taskbarMock.Object) sut = new DisplayMonitorOperation(displayMonitorMock.Object, loggerMock.Object, taskbarMock.Object);
{
SplashScreen = splashScreenMock.Object
};
} }
[TestMethod] [TestMethod]

View file

@ -11,7 +11,6 @@ using Moq;
using SafeExamBrowser.Client.Behaviour.Operations; using SafeExamBrowser.Client.Behaviour.Operations;
using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.Monitoring; using SafeExamBrowser.Contracts.Monitoring;
using SafeExamBrowser.Contracts.UserInterface;
using SafeExamBrowser.Contracts.WindowsApi; using SafeExamBrowser.Contracts.WindowsApi;
namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations
@ -22,7 +21,6 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations
private Mock<IKeyboardInterceptor> keyboardInterceptorMock; private Mock<IKeyboardInterceptor> keyboardInterceptorMock;
private Mock<ILogger> loggerMock; private Mock<ILogger> loggerMock;
private Mock<INativeMethods> nativeMethodsMock; private Mock<INativeMethods> nativeMethodsMock;
private Mock<ISplashScreen> splashScreenMock;
private KeyboardInterceptorOperation sut; private KeyboardInterceptorOperation sut;
@ -32,12 +30,8 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations
keyboardInterceptorMock = new Mock<IKeyboardInterceptor>(); keyboardInterceptorMock = new Mock<IKeyboardInterceptor>();
loggerMock = new Mock<ILogger>(); loggerMock = new Mock<ILogger>();
nativeMethodsMock = new Mock<INativeMethods>(); nativeMethodsMock = new Mock<INativeMethods>();
splashScreenMock = new Mock<ISplashScreen>();
sut = new KeyboardInterceptorOperation(keyboardInterceptorMock.Object, loggerMock.Object, nativeMethodsMock.Object) sut = new KeyboardInterceptorOperation(keyboardInterceptorMock.Object, loggerMock.Object, nativeMethodsMock.Object);
{
SplashScreen = splashScreenMock.Object
};
} }
[TestMethod] [TestMethod]

View file

@ -11,7 +11,6 @@ using Moq;
using SafeExamBrowser.Client.Behaviour.Operations; using SafeExamBrowser.Client.Behaviour.Operations;
using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.Monitoring; using SafeExamBrowser.Contracts.Monitoring;
using SafeExamBrowser.Contracts.UserInterface;
using SafeExamBrowser.Contracts.WindowsApi; using SafeExamBrowser.Contracts.WindowsApi;
namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations
@ -22,7 +21,6 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations
private Mock<IMouseInterceptor> mouseInterceptorMock; private Mock<IMouseInterceptor> mouseInterceptorMock;
private Mock<ILogger> loggerMock; private Mock<ILogger> loggerMock;
private Mock<INativeMethods> nativeMethodsMock; private Mock<INativeMethods> nativeMethodsMock;
private Mock<ISplashScreen> splashScreenMock;
private MouseInterceptorOperation sut; private MouseInterceptorOperation sut;
@ -32,12 +30,8 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations
mouseInterceptorMock = new Mock<IMouseInterceptor>(); mouseInterceptorMock = new Mock<IMouseInterceptor>();
loggerMock = new Mock<ILogger>(); loggerMock = new Mock<ILogger>();
nativeMethodsMock = new Mock<INativeMethods>(); nativeMethodsMock = new Mock<INativeMethods>();
splashScreenMock = new Mock<ISplashScreen>();
sut = new MouseInterceptorOperation(loggerMock.Object, mouseInterceptorMock.Object, nativeMethodsMock.Object) sut = new MouseInterceptorOperation(loggerMock.Object, mouseInterceptorMock.Object, nativeMethodsMock.Object);
{
SplashScreen = splashScreenMock.Object
};
} }
[TestMethod] [TestMethod]

View file

@ -11,7 +11,6 @@ using Moq;
using SafeExamBrowser.Client.Behaviour.Operations; using SafeExamBrowser.Client.Behaviour.Operations;
using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.Monitoring; using SafeExamBrowser.Contracts.Monitoring;
using SafeExamBrowser.Contracts.UserInterface;
namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations
{ {
@ -20,7 +19,6 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations
{ {
private Mock<ILogger> loggerMock; private Mock<ILogger> loggerMock;
private Mock<IProcessMonitor> processMonitorMock; private Mock<IProcessMonitor> processMonitorMock;
private Mock<ISplashScreen> splashScreenMock;
private ProcessMonitorOperation sut; private ProcessMonitorOperation sut;
@ -29,12 +27,8 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations
{ {
loggerMock = new Mock<ILogger>(); loggerMock = new Mock<ILogger>();
processMonitorMock = new Mock<IProcessMonitor>(); processMonitorMock = new Mock<IProcessMonitor>();
splashScreenMock = new Mock<ISplashScreen>();
sut = new ProcessMonitorOperation(loggerMock.Object, processMonitorMock.Object) sut = new ProcessMonitorOperation(loggerMock.Object, processMonitorMock.Object);
{
SplashScreen = splashScreenMock.Object
};
} }
[TestMethod] [TestMethod]

View file

@ -24,7 +24,6 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations
{ {
private Mock<ILogger> loggerMock; private Mock<ILogger> loggerMock;
private Mock<ITaskbarSettings> settingsMock; private Mock<ITaskbarSettings> settingsMock;
private Mock<ISplashScreen> splashScreenMock;
private Mock<ISystemComponent<ISystemKeyboardLayoutControl>> keyboardLayoutMock; private Mock<ISystemComponent<ISystemKeyboardLayoutControl>> keyboardLayoutMock;
private Mock<ISystemComponent<ISystemPowerSupplyControl>> powerSupplyMock; private Mock<ISystemComponent<ISystemPowerSupplyControl>> powerSupplyMock;
private Mock<ISystemComponent<ISystemWirelessNetworkControl>> wirelessNetworkMock; private Mock<ISystemComponent<ISystemWirelessNetworkControl>> wirelessNetworkMock;
@ -40,7 +39,6 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations
{ {
loggerMock = new Mock<ILogger>(); loggerMock = new Mock<ILogger>();
settingsMock = new Mock<ITaskbarSettings>(); settingsMock = new Mock<ITaskbarSettings>();
splashScreenMock = new Mock<ISplashScreen>();
keyboardLayoutMock = new Mock<ISystemComponent<ISystemKeyboardLayoutControl>>(); keyboardLayoutMock = new Mock<ISystemComponent<ISystemKeyboardLayoutControl>>();
powerSupplyMock = new Mock<ISystemComponent<ISystemPowerSupplyControl>>(); powerSupplyMock = new Mock<ISystemComponent<ISystemPowerSupplyControl>>();
wirelessNetworkMock = new Mock<ISystemComponent<ISystemWirelessNetworkControl>>(); wirelessNetworkMock = new Mock<ISystemComponent<ISystemWirelessNetworkControl>>();
@ -64,10 +62,7 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations
systemInfoMock.Object, systemInfoMock.Object,
taskbarMock.Object, taskbarMock.Object,
textMock.Object, textMock.Object,
uiFactoryMock.Object) uiFactoryMock.Object);
{
SplashScreen = splashScreenMock.Object
};
} }
[TestMethod] [TestMethod]

View file

@ -11,7 +11,6 @@ using Moq;
using SafeExamBrowser.Client.Behaviour.Operations; using SafeExamBrowser.Client.Behaviour.Operations;
using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.Monitoring; using SafeExamBrowser.Contracts.Monitoring;
using SafeExamBrowser.Contracts.UserInterface;
namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations
{ {
@ -19,7 +18,6 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations
public class WindowMonitorOperationTests public class WindowMonitorOperationTests
{ {
private Mock<ILogger> loggerMock; private Mock<ILogger> loggerMock;
private Mock<ISplashScreen> splashScreenMock;
private Mock<IWindowMonitor> windowMonitorMock; private Mock<IWindowMonitor> windowMonitorMock;
private WindowMonitorOperation sut; private WindowMonitorOperation sut;
@ -28,13 +26,9 @@ namespace SafeExamBrowser.Client.UnitTests.Behaviour.Operations
public void Initialize() public void Initialize()
{ {
loggerMock = new Mock<ILogger>(); loggerMock = new Mock<ILogger>();
splashScreenMock = new Mock<ISplashScreen>();
windowMonitorMock = new Mock<IWindowMonitor>(); windowMonitorMock = new Mock<IWindowMonitor>();
sut = new WindowMonitorOperation(loggerMock.Object, windowMonitorMock.Object) sut = new WindowMonitorOperation(loggerMock.Object, windowMonitorMock.Object);
{
SplashScreen = splashScreenMock.Object
};
} }
[TestMethod] [TestMethod]

View file

@ -25,7 +25,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
private IUserInterfaceFactory uiFactory; private IUserInterfaceFactory uiFactory;
public bool Abort { get; private set; } public bool Abort { get; private set; }
public ISplashScreen SplashScreen { private get; set; } public IProgressIndicator ProgressIndicator { private get; set; }
public BrowserOperation( public BrowserOperation(
IApplicationController browserController, IApplicationController browserController,
@ -44,7 +44,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
public void Perform() public void Perform()
{ {
logger.Info("Initializing browser..."); logger.Info("Initializing browser...");
SplashScreen.UpdateText(TextKey.SplashScreen_InitializeBrowser, true); ProgressIndicator?.UpdateText(TextKey.SplashScreen_InitializeBrowser, true);
var browserButton = uiFactory.CreateApplicationButton(browserInfo); var browserButton = uiFactory.CreateApplicationButton(browserInfo);
@ -62,7 +62,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
public void Revert() public void Revert()
{ {
logger.Info("Terminating browser..."); logger.Info("Terminating browser...");
SplashScreen.UpdateText(TextKey.SplashScreen_TerminateBrowser, true); ProgressIndicator?.UpdateText(TextKey.SplashScreen_TerminateBrowser, true);
browserController.Terminate(); browserController.Terminate();
} }

View file

@ -20,7 +20,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
private IClientController controller; private IClientController controller;
public bool Abort { get; private set; } public bool Abort { get; private set; }
public ISplashScreen SplashScreen { private get; set; } public IProgressIndicator ProgressIndicator { private get; set; }
public ClientControllerOperation(IClientController controller, ILogger logger) public ClientControllerOperation(IClientController controller, ILogger logger)
{ {
@ -31,7 +31,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
public void Perform() public void Perform()
{ {
logger.Info("Starting event handling..."); logger.Info("Starting event handling...");
SplashScreen.UpdateText(TextKey.SplashScreen_StartEventHandling); ProgressIndicator?.UpdateText(TextKey.SplashScreen_StartEventHandling);
controller.Start(); controller.Start();
} }
@ -44,7 +44,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
public void Revert() public void Revert()
{ {
logger.Info("Stopping event handling..."); logger.Info("Stopping event handling...");
SplashScreen.UpdateText(TextKey.SplashScreen_StopEventHandling); ProgressIndicator?.UpdateText(TextKey.SplashScreen_StopEventHandling);
controller.Stop(); controller.Stop();
} }

View file

@ -20,7 +20,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
private INativeMethods nativeMethods; private INativeMethods nativeMethods;
public bool Abort { get; private set; } public bool Abort { get; private set; }
public ISplashScreen SplashScreen { private get; set; } public IProgressIndicator ProgressIndicator { private get; set; }
public ClipboardOperation(ILogger logger, INativeMethods nativeMethods) public ClipboardOperation(ILogger logger, INativeMethods nativeMethods)
{ {
@ -46,7 +46,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
private void EmptyClipboard() private void EmptyClipboard()
{ {
logger.Info("Emptying clipboard..."); logger.Info("Emptying clipboard...");
SplashScreen.UpdateText(TextKey.SplashScreen_EmptyClipboard); ProgressIndicator?.UpdateText(TextKey.SplashScreen_EmptyClipboard);
nativeMethods.EmptyClipboard(); nativeMethods.EmptyClipboard();
} }

View file

@ -22,7 +22,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
private ITaskbar taskbar; private ITaskbar taskbar;
public bool Abort { get; private set; } 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) public DisplayMonitorOperation(IDisplayMonitor displayMonitor, ILogger logger, ITaskbar taskbar)
{ {
@ -34,7 +34,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
public void Perform() public void Perform()
{ {
logger.Info("Initializing working area..."); logger.Info("Initializing working area...");
SplashScreen.UpdateText(TextKey.SplashScreen_InitializeWorkingArea); ProgressIndicator?.UpdateText(TextKey.SplashScreen_InitializeWorkingArea);
displayMonitor.PreventSleepMode(); displayMonitor.PreventSleepMode();
displayMonitor.InitializePrimaryDisplay(taskbar.GetAbsoluteHeight()); displayMonitor.InitializePrimaryDisplay(taskbar.GetAbsoluteHeight());
@ -49,7 +49,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
public void Revert() public void Revert()
{ {
logger.Info("Restoring working area..."); logger.Info("Restoring working area...");
SplashScreen.UpdateText(TextKey.SplashScreen_RestoreWorkingArea); ProgressIndicator?.UpdateText(TextKey.SplashScreen_RestoreWorkingArea);
displayMonitor.StopMonitoringDisplayChanges(); displayMonitor.StopMonitoringDisplayChanges();
displayMonitor.ResetPrimaryDisplay(); displayMonitor.ResetPrimaryDisplay();

View file

@ -22,7 +22,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
private INativeMethods nativeMethods; private INativeMethods nativeMethods;
public bool Abort { get; private set; } public bool Abort { get; private set; }
public ISplashScreen SplashScreen { private get; set; } public IProgressIndicator ProgressIndicator { private get; set; }
public KeyboardInterceptorOperation( public KeyboardInterceptorOperation(
IKeyboardInterceptor keyboardInterceptor, IKeyboardInterceptor keyboardInterceptor,
@ -37,7 +37,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
public void Perform() public void Perform()
{ {
logger.Info("Starting keyboard interception..."); logger.Info("Starting keyboard interception...");
SplashScreen.UpdateText(TextKey.SplashScreen_StartKeyboardInterception); ProgressIndicator?.UpdateText(TextKey.SplashScreen_StartKeyboardInterception);
nativeMethods.RegisterKeyboardHook(keyboardInterceptor); nativeMethods.RegisterKeyboardHook(keyboardInterceptor);
} }
@ -50,7 +50,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
public void Revert() public void Revert()
{ {
logger.Info("Stopping keyboard interception..."); logger.Info("Stopping keyboard interception...");
SplashScreen.UpdateText(TextKey.SplashScreen_StopKeyboardInterception); ProgressIndicator?.UpdateText(TextKey.SplashScreen_StopKeyboardInterception);
nativeMethods.DeregisterKeyboardHook(keyboardInterceptor); nativeMethods.DeregisterKeyboardHook(keyboardInterceptor);
} }

View file

@ -22,7 +22,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
private INativeMethods nativeMethods; private INativeMethods nativeMethods;
public bool Abort { get; private set; } public bool Abort { get; private set; }
public ISplashScreen SplashScreen { private get; set; } public IProgressIndicator ProgressIndicator { private get; set; }
public MouseInterceptorOperation( public MouseInterceptorOperation(
ILogger logger, ILogger logger,
@ -37,7 +37,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
public void Perform() public void Perform()
{ {
logger.Info("Starting mouse interception..."); logger.Info("Starting mouse interception...");
SplashScreen.UpdateText(TextKey.SplashScreen_StartMouseInterception); ProgressIndicator?.UpdateText(TextKey.SplashScreen_StartMouseInterception);
nativeMethods.RegisterMouseHook(mouseInterceptor); nativeMethods.RegisterMouseHook(mouseInterceptor);
} }
@ -50,7 +50,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
public void Revert() public void Revert()
{ {
logger.Info("Stopping mouse interception..."); logger.Info("Stopping mouse interception...");
SplashScreen.UpdateText(TextKey.SplashScreen_StopMouseInterception); ProgressIndicator?.UpdateText(TextKey.SplashScreen_StopMouseInterception);
nativeMethods.DeregisterMouseHook(mouseInterceptor); nativeMethods.DeregisterMouseHook(mouseInterceptor);
} }

View file

@ -20,7 +20,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
private IProcessMonitor processMonitor; private IProcessMonitor processMonitor;
public bool Abort { get; private set; } public bool Abort { get; private set; }
public ISplashScreen SplashScreen { private get; set; } public IProgressIndicator ProgressIndicator { private get; set; }
public ProcessMonitorOperation(ILogger logger, IProcessMonitor processMonitor) public ProcessMonitorOperation(ILogger logger, IProcessMonitor processMonitor)
{ {
@ -31,12 +31,12 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
public void Perform() public void Perform()
{ {
logger.Info("Initializing process monitoring..."); logger.Info("Initializing process monitoring...");
SplashScreen.UpdateText(TextKey.SplashScreen_WaitExplorerTermination, true); ProgressIndicator?.UpdateText(TextKey.SplashScreen_WaitExplorerTermination, true);
processMonitor.CloseExplorerShell(); processMonitor.CloseExplorerShell();
processMonitor.StartMonitoringExplorer(); processMonitor.StartMonitoringExplorer();
SplashScreen.UpdateText(TextKey.SplashScreen_InitializeProcessMonitoring); ProgressIndicator?.UpdateText(TextKey.SplashScreen_InitializeProcessMonitoring);
// TODO // TODO
} }
@ -49,11 +49,11 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
public void Revert() public void Revert()
{ {
logger.Info("Stopping process monitoring..."); logger.Info("Stopping process monitoring...");
SplashScreen.UpdateText(TextKey.SplashScreen_StopProcessMonitoring); ProgressIndicator?.UpdateText(TextKey.SplashScreen_StopProcessMonitoring);
// TODO // TODO
SplashScreen.UpdateText(TextKey.SplashScreen_WaitExplorerStartup, true); ProgressIndicator?.UpdateText(TextKey.SplashScreen_WaitExplorerStartup, true);
processMonitor.StopMonitoringExplorer(); processMonitor.StopMonitoringExplorer();
processMonitor.StartExplorerShell(); processMonitor.StartExplorerShell();

View file

@ -33,7 +33,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
private IText text; private IText text;
public bool Abort { get; private set; } public bool Abort { get; private set; }
public ISplashScreen SplashScreen { private get; set; } public IProgressIndicator ProgressIndicator { private get; set; }
public TaskbarOperation( public TaskbarOperation(
ILogger logger, ILogger logger,
@ -60,7 +60,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
public void Perform() public void Perform()
{ {
logger.Info("Initializing taskbar..."); logger.Info("Initializing taskbar...");
SplashScreen.UpdateText(TextKey.SplashScreen_InitializeTaskbar); ProgressIndicator?.UpdateText(TextKey.SplashScreen_InitializeTaskbar);
if (settings.AllowApplicationLog) if (settings.AllowApplicationLog)
{ {
@ -91,7 +91,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
public void Revert() public void Revert()
{ {
logger.Info("Terminating taskbar..."); logger.Info("Terminating taskbar...");
SplashScreen.UpdateText(TextKey.SplashScreen_TerminateTaskbar); ProgressIndicator?.UpdateText(TextKey.SplashScreen_TerminateTaskbar);
if (settings.AllowApplicationLog) if (settings.AllowApplicationLog)
{ {

View file

@ -20,7 +20,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
private IWindowMonitor windowMonitor; private IWindowMonitor windowMonitor;
public bool Abort { get; private set; } public bool Abort { get; private set; }
public ISplashScreen SplashScreen { private get; set; } public IProgressIndicator ProgressIndicator { private get; set; }
public WindowMonitorOperation(ILogger logger, IWindowMonitor windowMonitor) public WindowMonitorOperation(ILogger logger, IWindowMonitor windowMonitor)
{ {
@ -31,7 +31,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
public void Perform() public void Perform()
{ {
logger.Info("Initializing window monitoring..."); logger.Info("Initializing window monitoring...");
SplashScreen.UpdateText(TextKey.SplashScreen_InitializeWindowMonitoring); ProgressIndicator?.UpdateText(TextKey.SplashScreen_InitializeWindowMonitoring);
windowMonitor.HideAllWindows(); windowMonitor.HideAllWindows();
windowMonitor.StartMonitoringWindows(); windowMonitor.StartMonitoringWindows();
@ -45,7 +45,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
public void Revert() public void Revert()
{ {
logger.Info("Stopping window monitoring..."); logger.Info("Stopping window monitoring...");
SplashScreen.UpdateText(TextKey.SplashScreen_StopWindowMonitoring); ProgressIndicator?.UpdateText(TextKey.SplashScreen_StopWindowMonitoring);
windowMonitor.StopMonitoringWindows(); windowMonitor.StopMonitoringWindows();
windowMonitor.RestoreHiddenWindows(); windowMonitor.RestoreHiddenWindows();

View file

@ -6,9 +6,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * 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 namespace SafeExamBrowser.Contracts.Behaviour
{ {
public interface IRuntimeController public interface IRuntimeController
@ -21,6 +18,6 @@ namespace SafeExamBrowser.Contracts.Behaviour
/// <summary> /// <summary>
/// Tries to start the runtime. Returns <c>true</c> if successful, otherwise <c>false</c>. /// Tries to start the runtime. Returns <c>true</c> if successful, otherwise <c>false</c>.
/// </summary> /// </summary>
bool TryStart(Queue<IOperation> operations); bool TryStart();
} }
} }

View file

@ -13,14 +13,14 @@ namespace SafeExamBrowser.Contracts.Behaviour.Operations
public interface IOperation public interface IOperation
{ {
/// <summary> /// <summary>
/// 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.
/// </summary> /// </summary>
bool Abort { get; } bool Abort { get; }
/// <summary> /// <summary>
/// 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 <c>null</c>.
/// </summary> /// </summary>
ISplashScreen SplashScreen { set; } IProgressIndicator ProgressIndicator { set; }
/// <summary> /// <summary>
/// Performs the operation. /// Performs the operation.

View file

@ -6,24 +6,29 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * 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 namespace SafeExamBrowser.Contracts.Behaviour.Operations
{ {
public interface IOperationSequence public interface IOperationSequence
{ {
/// <summary> /// <summary>
/// Tries to perform the given sequence of operations. Returns <c>true</c> if the procedure was successful, <c>false</c> otherwise. /// The progress indicator to be used when performing any action. Will be ignored if <c>null</c>.
/// </summary> /// </summary>
bool TryPerform(Queue<IOperation> operations); IProgressIndicator ProgressIndicator { set; }
/// <summary> /// <summary>
/// Tries to repeat all operations of this sequence. Returns <c>true</c> if the procedure was successful, <c>false</c> otherwise. /// Tries to perform the operations of this sequence. Returns <c>true</c> if the procedure was successful, <c>false</c> otherwise.
/// </summary>
bool TryPerform();
/// <summary>
/// Tries to repeat the operations of this sequence. Returns <c>true</c> if the procedure was successful, <c>false</c> otherwise.
/// </summary> /// </summary>
bool TryRepeat(); bool TryRepeat();
/// <summary> /// <summary>
/// Tries to revert all operations of this sequence. Returns <c>true</c> if the procedure was successful, <c>false</c> otherwise. /// Tries to revert the operations of this sequence. Returns <c>true</c> if the procedure was successful, <c>false</c> otherwise.
/// </summary> /// </summary>
bool TryRevert(); bool TryRevert();
} }

View file

@ -44,7 +44,6 @@ namespace SafeExamBrowser.Contracts.I18n
SplashScreen_StartEventHandling, SplashScreen_StartEventHandling,
SplashScreen_StartKeyboardInterception, SplashScreen_StartKeyboardInterception,
SplashScreen_StartMouseInterception, SplashScreen_StartMouseInterception,
SplashScreen_StartupProcedure,
SplashScreen_StopEventHandling, SplashScreen_StopEventHandling,
SplashScreen_StopKeyboardInterception, SplashScreen_StopKeyboardInterception,
SplashScreen_StopMouseInterception, SplashScreen_StopMouseInterception,

View file

@ -108,6 +108,7 @@
<Compile Include="UserInterface\IBrowserControl.cs" /> <Compile Include="UserInterface\IBrowserControl.cs" />
<Compile Include="UserInterface\IBrowserWindow.cs" /> <Compile Include="UserInterface\IBrowserWindow.cs" />
<Compile Include="UserInterface\IMessageBox.cs" /> <Compile Include="UserInterface\IMessageBox.cs" />
<Compile Include="UserInterface\IProgressIndicator.cs" />
<Compile Include="UserInterface\IRuntimeWindow.cs" /> <Compile Include="UserInterface\IRuntimeWindow.cs" />
<Compile Include="UserInterface\MessageBoxResult.cs" /> <Compile Include="UserInterface\MessageBoxResult.cs" />
<Compile Include="UserInterface\Taskbar\INotificationButton.cs" /> <Compile Include="UserInterface\Taskbar\INotificationButton.cs" />

View file

@ -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
{
/// <summary>
/// Updates the progress value according to the specified amount.
/// </summary>
void Progress(int amount = 1);
/// <summary>
/// Regresses the progress value according to the specified amount.
/// </summary>
void Regress(int amount = 1);
/// <summary>
/// Sets the style of the progress indicator to indeterminate (<c>Progress</c> and <c>Regress</c> won't have any effect when called).
/// </summary>
void SetIndeterminate();
/// <summary>
/// Sets the maximum progress value.
/// </summary>
void SetMaxValue(int max);
/// <summary>
/// Sets the current progress value.
/// </summary>
void SetValue(int value);
/// <summary>
/// Updates the status text. If the busy flag is set, an animation will be shown to indicate a long-running operation.
/// </summary>
void UpdateText(TextKey key, bool showBusyIndication = false);
}
}

View file

@ -6,17 +6,20 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.Logging;
namespace SafeExamBrowser.Contracts.UserInterface namespace SafeExamBrowser.Contracts.UserInterface
{ {
public interface IRuntimeWindow : ILogObserver, IWindow public interface IRuntimeWindow : ILogObserver, IProgressIndicator, IWindow
{ {
/// <summary> /// <summary>
/// Updates the status text of the runtime window. If the busy flag is set, /// Hides the progress bar.
/// the window will show an animation to indicate a long-running operation.
/// </summary> /// </summary>
void UpdateStatus(TextKey key, bool showBusyIndication = false); void HideProgressBar();
/// <summary>
/// Shows the progress bar.
/// </summary>
void ShowProgressBar();
} }
} }

View file

@ -6,37 +6,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
using SafeExamBrowser.Contracts.I18n;
namespace SafeExamBrowser.Contracts.UserInterface namespace SafeExamBrowser.Contracts.UserInterface
{ {
public interface ISplashScreen : IWindow public interface ISplashScreen : IProgressIndicator, IWindow
{ {
/// <summary>
/// Updates the progress bar of the splash screen according to the specified amount.
/// </summary>
void Progress(int amount = 1);
/// <summary>
/// Regresses the progress bar of the splash screen according to the specified amount.
/// </summary>
void Regress(int amount = 1);
/// <summary>
/// Sets the style of the progress bar to indeterminate, i.e. <c>Progress</c> and
/// <c>Regress</c> won't have any effect when called.
/// </summary>
void SetIndeterminate();
/// <summary>
/// Set the maximum of the splash screen's progress bar.
/// </summary>
void SetMaxProgress(int max);
/// <summary>
/// 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.
/// </summary>
void UpdateText(TextKey key, bool showBusyIndication = false);
} }
} }

View file

@ -10,7 +10,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq; using Moq;
using SafeExamBrowser.Contracts.I18n; using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.UserInterface;
using SafeExamBrowser.Core.Behaviour.Operations; using SafeExamBrowser.Core.Behaviour.Operations;
namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations
@ -19,7 +18,6 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations
public class I18nOperationTests public class I18nOperationTests
{ {
private Mock<ILogger> loggerMock; private Mock<ILogger> loggerMock;
private Mock<ISplashScreen> splashScreenMock;
private Mock<IText> textMock; private Mock<IText> textMock;
private I18nOperation sut; private I18nOperation sut;
@ -28,13 +26,9 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations
public void Initialize() public void Initialize()
{ {
loggerMock = new Mock<ILogger>(); loggerMock = new Mock<ILogger>();
splashScreenMock = new Mock<ISplashScreen>();
textMock = new Mock<IText>(); textMock = new Mock<IText>();
sut = new I18nOperation(loggerMock.Object, textMock.Object) sut = new I18nOperation(loggerMock.Object, textMock.Object);
{
SplashScreen = splashScreenMock.Object
};
} }
[TestMethod] [TestMethod]

View file

@ -11,8 +11,6 @@ using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq; using Moq;
using SafeExamBrowser.Contracts.Behaviour.Operations; using SafeExamBrowser.Contracts.Behaviour.Operations;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.UserInterface; using SafeExamBrowser.Contracts.UserInterface;
using SafeExamBrowser.Core.Behaviour.Operations; using SafeExamBrowser.Core.Behaviour.Operations;
@ -23,28 +21,17 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations
public class OperationSequenceTests public class OperationSequenceTests
{ {
private Mock<ILogger> loggerMock; private Mock<ILogger> loggerMock;
private Mock<IRuntimeInfo> runtimeInfoMock;
private Mock<IText> textMock;
private Mock<IUserInterfaceFactory> uiFactoryMock;
private IOperationSequence sut;
[TestInitialize] [TestInitialize]
public void Initialize() public void Initialize()
{ {
loggerMock = new Mock<ILogger>(); loggerMock = new Mock<ILogger>();
runtimeInfoMock = new Mock<IRuntimeInfo>();
textMock = new Mock<IText>();
uiFactoryMock = new Mock<IUserInterfaceFactory>();
uiFactoryMock.Setup(f => f.CreateSplashScreen(runtimeInfoMock.Object, textMock.Object)).Returns(new Mock<ISplashScreen>().Object);
sut = new OperationSequence(loggerMock.Object, runtimeInfoMock.Object, textMock.Object, uiFactoryMock.Object);
} }
#region Perform Tests #region Perform Tests
[TestMethod] [TestMethod]
public void MustCorrectlyAbortProcess() public void MustCorrectlyAbortPerform()
{ {
var operationA = new Mock<IOperation>(); var operationA = new Mock<IOperation>();
var operationB = new Mock<IOperation>(); var operationB = new Mock<IOperation>();
@ -57,7 +44,8 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations
operations.Enqueue(operationB.Object); operations.Enqueue(operationB.Object);
operations.Enqueue(operationC.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.Perform(), Times.Once);
operationA.Verify(o => o.Revert(), 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(operationB.Object);
operations.Enqueue(operationC.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.Perform(), Times.Once);
operationA.Verify(o => o.Revert(), Times.Never); operationA.Verify(o => o.Revert(), Times.Never);
@ -110,7 +99,8 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations
operations.Enqueue(operationB.Object); operations.Enqueue(operationB.Object);
operations.Enqueue(operationC.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(success);
Assert.IsTrue(a == 1); Assert.IsTrue(a == 1);
@ -134,7 +124,8 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations
operations.Enqueue(operationC.Object); operations.Enqueue(operationC.Object);
operations.Enqueue(operationD.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.Perform(), Times.Once);
operationA.Verify(o => o.Revert(), 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(operationC.Object);
operations.Enqueue(operationD.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.IsFalse(success);
Assert.IsTrue(d == 0); Assert.IsTrue(d == 0);
@ -195,7 +187,8 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations
operations.Enqueue(operationB.Object); operations.Enqueue(operationB.Object);
operations.Enqueue(operationC.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.Perform(), Times.Once);
operationA.Verify(o => o.Revert(), Times.Once); operationA.Verify(o => o.Revert(), Times.Once);
@ -208,18 +201,23 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations
[TestMethod] [TestMethod]
public void MustSucceedWithEmptyQueue() public void MustSucceedWithEmptyQueue()
{ {
var result = sut.TryPerform(new Queue<IOperation>()); var sut = new OperationSequence(loggerMock.Object, new Queue<IOperation>());
var success = sut.TryPerform();
Assert.IsTrue(result); Assert.IsTrue(success);
} }
[TestMethod] [TestMethod]
public void MustNotFailInCaseOfUnexpectedError() public void MustNotFailInCaseOfUnexpectedError()
{ {
uiFactoryMock.Setup(l => l.CreateSplashScreen(It.IsAny<IRuntimeInfo>(), It.IsAny<IText>())).Throws(new Exception()); var sut = new OperationSequence(loggerMock.Object, new Queue<IOperation>());
var indicatorMock = new Mock<IProgressIndicator>();
var success = sut.TryPerform(new Queue<IOperation>()); indicatorMock.Setup(i => i.SetMaxValue(It.IsAny<int>())).Throws<Exception>();
sut.ProgressIndicator = indicatorMock.Object;
var success = sut.TryPerform();
Assert.IsFalse(success); Assert.IsFalse(success);
} }
@ -229,10 +227,147 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations
#region Repeat Tests #region Repeat Tests
[TestMethod] [TestMethod]
public void Fail() public void MustCorrectlyAbortRepeat()
{ {
// TODO var operationA = new Mock<IOperation>();
Assert.Fail(); var operationB = new Mock<IOperation>();
var operationC = new Mock<IOperation>();
var operations = new Queue<IOperation>();
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<IOperation>();
var operationB = new Mock<IOperation>();
var operationC = new Mock<IOperation>();
var operations = new Queue<IOperation>();
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<IOperation>();
var operationB = new Mock<IOperation>();
var operationC = new Mock<IOperation>();
var operations = new Queue<IOperation>();
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<IOperation>();
var operationB = new Mock<IOperation>();
var operationC = new Mock<IOperation>();
var operationD = new Mock<IOperation>();
var operations = new Queue<IOperation>();
operationC.Setup(o => o.Repeat()).Throws<Exception>();
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<IOperation>());
var success = sut.TryRepeat();
Assert.IsTrue(success);
}
[TestMethod]
public void MustSucceedRepeatingWithoutCallingPerform()
{
var sut = new OperationSequence(loggerMock.Object, new Queue<IOperation>());
var success = sut.TryRepeat();
Assert.IsTrue(success);
}
[TestMethod]
public void MustNotFailInCaseOfUnexpectedErrorWhenRepeating()
{
var sut = new OperationSequence(loggerMock.Object, new Queue<IOperation>());
var indicatorMock = new Mock<IProgressIndicator>();
indicatorMock.Setup(i => i.SetMaxValue(It.IsAny<int>())).Throws<Exception>();
sut.ProgressIndicator = indicatorMock.Object;
var success = sut.TryRepeat();
Assert.IsFalse(success);
} }
#endregion #endregion
@ -251,7 +386,9 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations
operations.Enqueue(operationB.Object); operations.Enqueue(operationB.Object);
operations.Enqueue(operationC.Object); operations.Enqueue(operationC.Object);
sut.TryPerform(operations); var sut = new OperationSequence(loggerMock.Object, operations);
sut.TryPerform();
var success = sut.TryRevert(); var success = sut.TryRevert();
@ -279,7 +416,9 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations
operations.Enqueue(operationB.Object); operations.Enqueue(operationB.Object);
operations.Enqueue(operationC.Object); operations.Enqueue(operationC.Object);
sut.TryPerform(operations); var sut = new OperationSequence(loggerMock.Object, operations);
sut.TryPerform();
var success = sut.TryRevert(); var success = sut.TryRevert();
@ -305,7 +444,9 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations
operations.Enqueue(operationB.Object); operations.Enqueue(operationB.Object);
operations.Enqueue(operationC.Object); operations.Enqueue(operationC.Object);
sut.TryPerform(operations); var sut = new OperationSequence(loggerMock.Object, operations);
sut.TryPerform();
var success = sut.TryRevert(); var success = sut.TryRevert();
@ -330,7 +471,9 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations
operations.Enqueue(operationB.Object); operations.Enqueue(operationB.Object);
operations.Enqueue(operationC.Object); operations.Enqueue(operationC.Object);
sut.TryPerform(operations); var sut = new OperationSequence(loggerMock.Object, operations);
sut.TryPerform();
var success = sut.TryRevert(); var success = sut.TryRevert();
@ -342,15 +485,18 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations
} }
[TestMethod] [TestMethod]
public void MustNotFailWithEmptyQueueWhenReverting() public void MustSucceedWithEmptyQueueWhenReverting()
{ {
sut.TryPerform(new Queue<IOperation>()); var sut = new OperationSequence(loggerMock.Object, new Queue<IOperation>());
sut.TryPerform();
sut.TryRevert(); sut.TryRevert();
} }
[TestMethod] [TestMethod]
public void MustNotFailWithoutPerformWhenReverting() public void MustSucceedRevertingWithoutCallingPerform()
{ {
var sut = new OperationSequence(loggerMock.Object, new Queue<IOperation>());
var success = sut.TryRevert(); var success = sut.TryRevert();
Assert.IsTrue(success); Assert.IsTrue(success);
@ -359,8 +505,15 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour.Operations
[TestMethod] [TestMethod]
public void MustNotFailInCaseOfUnexpectedErrorWhenReverting() public void MustNotFailInCaseOfUnexpectedErrorWhenReverting()
{ {
uiFactoryMock.Setup(l => l.CreateSplashScreen(It.IsAny<IRuntimeInfo>(), It.IsAny<IText>())).Throws(new Exception()); var sut = new OperationSequence(loggerMock.Object, new Queue<IOperation>());
sut.TryRevert(); var indicatorMock = new Mock<IProgressIndicator>();
indicatorMock.Setup(i => i.SetMaxValue(It.IsAny<int>())).Throws<Exception>();
sut.ProgressIndicator = indicatorMock.Object;
var success = sut.TryRevert();
Assert.IsFalse(success);
} }
#endregion #endregion

View file

@ -23,7 +23,7 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
private IText text; private IText text;
public bool Abort { get; private set; } public bool Abort { get; private set; }
public ISplashScreen SplashScreen { private get; set; } public IProgressIndicator ProgressIndicator { private get; set; }
public I18nOperation(ILogger logger, IText text) public I18nOperation(ILogger logger, IText text)
{ {

View file

@ -10,8 +10,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using SafeExamBrowser.Contracts.Behaviour.Operations; using SafeExamBrowser.Contracts.Behaviour.Operations;
using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.UserInterface; using SafeExamBrowser.Contracts.UserInterface;
@ -20,42 +18,34 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
public class OperationSequence : IOperationSequence public class OperationSequence : IOperationSequence
{ {
private ILogger logger; private ILogger logger;
private IRuntimeInfo runtimeInfo; private Queue<IOperation> operations = new Queue<IOperation>();
private ISplashScreen splashScreen;
private IText text;
private IUserInterfaceFactory uiFactory;
private Stack<IOperation> stack = new Stack<IOperation>(); private Stack<IOperation> stack = new Stack<IOperation>();
public OperationSequence(ILogger logger, IRuntimeInfo runtimeInfo, IText text, IUserInterfaceFactory uiFactory) public IProgressIndicator ProgressIndicator { private get; set; }
public OperationSequence(ILogger logger, Queue<IOperation> operations)
{ {
this.logger = logger; this.logger = logger;
this.runtimeInfo = runtimeInfo; this.operations = new Queue<IOperation>(operations);
this.text = text;
this.uiFactory = uiFactory;
} }
public bool TryPerform(Queue<IOperation> operations) public bool TryPerform()
{ {
var success = false; var success = false;
try try
{ {
Initialize(operations.Count); Initialize();
success = Perform(operations); success = Perform();
if (!success) if (!success)
{ {
RevertOperations(); Revert();
} }
} }
catch (Exception e) catch (Exception e)
{ {
logger.Error($"Failed to perform operations!", e); logger.Error("Failed to perform operations!", e);
}
finally
{
Finish();
} }
return success; return success;
@ -63,7 +53,19 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
public bool TryRepeat() 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() public bool TryRevert()
@ -73,46 +75,38 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
try try
{ {
Initialize(); Initialize();
success = RevertOperations(false); success = Revert(false);
} }
catch (Exception e) catch (Exception e)
{ {
logger.Error($"Failed to revert operations!", e); logger.Error("Failed to revert operations!", e);
}
finally
{
Finish();
} }
return success; return success;
} }
private void Initialize(int? operationCount = null) private void Initialize(bool indeterminate = false)
{ {
splashScreen = uiFactory.CreateSplashScreen(runtimeInfo, text); if (indeterminate)
if (operationCount.HasValue)
{ {
splashScreen.SetMaxProgress(operationCount.Value); ProgressIndicator?.SetIndeterminate();
} }
else else
{ {
splashScreen.SetIndeterminate(); ProgressIndicator?.SetValue(0);
ProgressIndicator?.SetMaxValue(operations.Count);
} }
splashScreen.UpdateText(TextKey.SplashScreen_StartupProcedure);
splashScreen.Show();
} }
private bool Perform(Queue<IOperation> operations) private bool Perform()
{ {
foreach (var operation in operations) foreach (var operation in operations)
{ {
stack.Push(operation); stack.Push(operation);
operation.SplashScreen = splashScreen;
try try
{ {
operation.ProgressIndicator = ProgressIndicator;
operation.Perform(); operation.Perform();
} }
catch (Exception e) catch (Exception e)
@ -127,13 +121,40 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
return false; return false;
} }
splashScreen.Progress(); ProgressIndicator?.Progress();
} }
return true; 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; var success = true;
@ -143,6 +164,7 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
try try
{ {
operation.ProgressIndicator = ProgressIndicator;
operation.Revert(); operation.Revert();
} }
catch (Exception e) catch (Exception e)
@ -153,16 +175,11 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
if (regress) if (regress)
{ {
splashScreen.Regress(); ProgressIndicator?.Regress();
} }
} }
return success; return success;
} }
private void Finish()
{
splashScreen?.Close();
}
} }
} }

View file

@ -87,9 +87,6 @@
<Entry key="SplashScreen_StartMouseInterception"> <Entry key="SplashScreen_StartMouseInterception">
Starting mouse interception Starting mouse interception
</Entry> </Entry>
<Entry key="SplashScreen_StartupProcedure">
Initiating startup procedure
</Entry>
<Entry key="SplashScreen_StopEventHandling"> <Entry key="SplashScreen_StopEventHandling">
Stopping event handling Stopping event handling
</Entry> </Entry>

View file

@ -26,7 +26,6 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
private Mock<IRuntimeInfo> info; private Mock<IRuntimeInfo> info;
private Mock<ISettingsRepository> repository; private Mock<ISettingsRepository> repository;
private Mock<ISettings> settings; private Mock<ISettings> settings;
private Mock<ISplashScreen> splashScreen;
private Mock<IText> text; private Mock<IText> text;
private Mock<IUserInterfaceFactory> uiFactory; private Mock<IUserInterfaceFactory> uiFactory;
private ConfigurationOperation sut; private ConfigurationOperation sut;
@ -38,7 +37,6 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
info = new Mock<IRuntimeInfo>(); info = new Mock<IRuntimeInfo>();
repository = new Mock<ISettingsRepository>(); repository = new Mock<ISettingsRepository>();
settings = new Mock<ISettings>(); settings = new Mock<ISettings>();
splashScreen = new Mock<ISplashScreen>();
text = new Mock<IText>(); text = new Mock<IText>();
uiFactory = new Mock<IUserInterfaceFactory>(); uiFactory = new Mock<IUserInterfaceFactory>();
@ -54,17 +52,11 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
{ {
repository.Setup(r => r.LoadDefaults()); repository.Setup(r => r.LoadDefaults());
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null) sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null);
{
SplashScreen = splashScreen.Object
};
sut.Perform(); sut.Perform();
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, new string[] { }) sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, new string[] { });
{
SplashScreen = splashScreen.Object
};
sut.Perform(); sut.Perform();
@ -76,10 +68,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
{ {
var path = @"an/invalid\path.'*%yolo/()"; var path = @"an/invalid\path.'*%yolo/()";
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, new [] { "blubb.exe", path }) sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, new [] { "blubb.exe", path });
{
SplashScreen = splashScreen.Object
};
sut.Perform(); sut.Perform();
} }
@ -93,10 +82,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
info.SetupGet(r => r.ProgramDataFolder).Returns(location); info.SetupGet(r => r.ProgramDataFolder).Returns(location);
info.SetupGet(r => r.AppDataFolder).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 }) sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, new[] { "blubb.exe", path });
{
SplashScreen = splashScreen.Object
};
sut.Perform(); sut.Perform();
@ -111,10 +97,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
info.SetupGet(r => r.ProgramDataFolder).Returns(location); info.SetupGet(r => r.ProgramDataFolder).Returns(location);
info.SetupGet(r => r.AppDataFolder).Returns($@"{location}\WRONG"); info.SetupGet(r => r.AppDataFolder).Returns($@"{location}\WRONG");
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null) sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null);
{
SplashScreen = splashScreen.Object
};
sut.Perform(); sut.Perform();
@ -128,10 +111,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
info.SetupGet(r => r.AppDataFolder).Returns(location); info.SetupGet(r => r.AppDataFolder).Returns(location);
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null) sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null);
{
SplashScreen = splashScreen.Object
};
sut.Perform(); sut.Perform();
@ -141,10 +121,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
[TestMethod] [TestMethod]
public void MustFallbackToDefaultsAsLastPrio() public void MustFallbackToDefaultsAsLastPrio()
{ {
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null) sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null);
{
SplashScreen = splashScreen.Object
};
sut.Perform(); sut.Perform();
@ -159,10 +136,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
info.SetupGet(r => r.ProgramDataFolder).Returns(location); info.SetupGet(r => r.ProgramDataFolder).Returns(location);
uiFactory.Setup(u => u.Show(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MessageBoxAction>(), It.IsAny<MessageBoxIcon>())).Returns(MessageBoxResult.Yes); uiFactory.Setup(u => u.Show(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MessageBoxAction>(), It.IsAny<MessageBoxIcon>())).Returns(MessageBoxResult.Yes);
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null) sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null);
{
SplashScreen = splashScreen.Object
};
sut.Perform(); sut.Perform();
@ -174,10 +148,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
{ {
uiFactory.Setup(u => u.Show(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MessageBoxAction>(), It.IsAny<MessageBoxIcon>())).Returns(MessageBoxResult.No); uiFactory.Setup(u => u.Show(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MessageBoxAction>(), It.IsAny<MessageBoxIcon>())).Returns(MessageBoxResult.No);
sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null) sut = new ConfigurationOperation(logger.Object, info.Object, repository.Object, text.Object, uiFactory.Object, null);
{
SplashScreen = splashScreen.Object
};
sut.Perform(); sut.Perform();

View file

@ -24,7 +24,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
private Mock<ILogger> logger; private Mock<ILogger> logger;
private Mock<IServiceProxy> service; private Mock<IServiceProxy> service;
private Mock<ISettingsRepository> settings; private Mock<ISettingsRepository> settings;
private Mock<ISplashScreen> splashScreen; private Mock<IProgressIndicator> progressIndicator;
private Mock<IText> text; private Mock<IText> text;
private ServiceOperation sut; private ServiceOperation sut;
@ -34,13 +34,10 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
logger = new Mock<ILogger>(); logger = new Mock<ILogger>();
service = new Mock<IServiceProxy>(); service = new Mock<IServiceProxy>();
settings = new Mock<ISettingsRepository>(); settings = new Mock<ISettingsRepository>();
splashScreen = new Mock<ISplashScreen>(); progressIndicator = new Mock<IProgressIndicator>();
text = new Mock<IText>(); text = new Mock<IText>();
sut = new ServiceOperation(logger.Object, service.Object, settings.Object, text.Object) sut = new ServiceOperation(logger.Object, service.Object, settings.Object, text.Object);
{
SplashScreen = splashScreen.Object
};
} }
[TestMethod] [TestMethod]

View file

@ -60,7 +60,7 @@ namespace SafeExamBrowser.Runtime
instances.BuildObjectGraph(); instances.BuildObjectGraph();
instances.LogStartupInformation(); instances.LogStartupInformation();
var success = instances.RuntimeController.TryStart(instances.StartupOperations); var success = instances.RuntimeController.TryStart();
if (!success) if (!success)
{ {

View file

@ -27,7 +27,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
private string[] commandLineArgs; private string[] commandLineArgs;
public bool Abort { get; private set; } public bool Abort { get; private set; }
public ISplashScreen SplashScreen { private get; set; } public IProgressIndicator ProgressIndicator { private get; set; }
public ConfigurationOperation( public ConfigurationOperation(
ILogger logger, ILogger logger,
@ -48,7 +48,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
public void Perform() public void Perform()
{ {
logger.Info("Initializing application configuration..."); logger.Info("Initializing application configuration...");
SplashScreen.UpdateText(TextKey.SplashScreen_InitializeConfiguration); ProgressIndicator?.UpdateText(TextKey.SplashScreen_InitializeConfiguration);
ISettings settings; ISettings settings;
var isValidUri = TryGetSettingsUri(out Uri uri); var isValidUri = TryGetSettingsUri(out Uri uri);
@ -73,7 +73,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
public void Repeat() 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() public void Revert()

View file

@ -21,7 +21,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
private KioskMode kioskMode; private KioskMode kioskMode;
public bool Abort { get; private set; } public bool Abort { get; private set; }
public ISplashScreen SplashScreen { private get; set; } public IProgressIndicator ProgressIndicator { private get; set; }
public KioskModeOperation(ILogger logger, ISettingsRepository settingsRepository) public KioskModeOperation(ILogger logger, ISettingsRepository settingsRepository)
{ {
@ -34,7 +34,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
kioskMode = settingsRepository.Current.KioskMode; kioskMode = settingsRepository.Current.KioskMode;
logger.Info($"Initializing kiosk mode '{kioskMode}'..."); logger.Info($"Initializing kiosk mode '{kioskMode}'...");
SplashScreen.UpdateText(TextKey.SplashScreen_InitializeKioskMode); ProgressIndicator?.UpdateText(TextKey.SplashScreen_InitializeKioskMode);
if (kioskMode == KioskMode.CreateNewDesktop) if (kioskMode == KioskMode.CreateNewDesktop)
{ {
@ -54,7 +54,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
public void Revert() public void Revert()
{ {
logger.Info($"Reverting kiosk mode '{kioskMode}'..."); logger.Info($"Reverting kiosk mode '{kioskMode}'...");
SplashScreen.UpdateText(TextKey.SplashScreen_RevertKioskMode); ProgressIndicator?.UpdateText(TextKey.SplashScreen_RevertKioskMode);
if (kioskMode == KioskMode.CreateNewDesktop) if (kioskMode == KioskMode.CreateNewDesktop)
{ {

View file

@ -26,7 +26,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
private IText text; private IText text;
public bool Abort { get; private set; } 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) public ServiceOperation(ILogger logger, IServiceProxy service, ISettingsRepository settingsRepository, IText text)
{ {
@ -39,7 +39,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
public void Perform() public void Perform()
{ {
logger.Info($"Initializing service connection..."); logger.Info($"Initializing service connection...");
SplashScreen.UpdateText(TextKey.SplashScreen_InitializeServiceConnection); ProgressIndicator?.UpdateText(TextKey.SplashScreen_InitializeServiceConnection);
try try
{ {
@ -71,7 +71,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
public void Revert() public void Revert()
{ {
logger.Info("Closing service connection..."); logger.Info("Closing service connection...");
SplashScreen.UpdateText(TextKey.SplashScreen_CloseServiceConnection); ProgressIndicator?.UpdateText(TextKey.SplashScreen_CloseServiceConnection);
if (serviceAvailable) if (serviceAvailable)
{ {

View file

@ -7,7 +7,6 @@
*/ */
using System; using System;
using System.Collections.Generic;
using SafeExamBrowser.Contracts.Behaviour; using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Behaviour.Operations; using SafeExamBrowser.Contracts.Behaviour.Operations;
using SafeExamBrowser.Contracts.Communication; using SafeExamBrowser.Contracts.Communication;
@ -22,18 +21,21 @@ namespace SafeExamBrowser.Runtime.Behaviour
internal class RuntimeController : IRuntimeController internal class RuntimeController : IRuntimeController
{ {
private ILogger logger; private ILogger logger;
private IOperationSequence bootstrapSequence;
private IOperationSequence sessionSequence;
private IRuntimeInfo runtimeInfo; private IRuntimeInfo runtimeInfo;
private IRuntimeWindow runtimeWindow; private IRuntimeWindow runtimeWindow;
private IServiceProxy serviceProxy; private IServiceProxy serviceProxy;
private ISettingsRepository settingsRepository; private ISettingsRepository settingsRepository;
private IOperationSequence operationSequence; private ISplashScreen splashScreen;
private Action terminationCallback; private Action terminationCallback;
private IText text; private IText text;
private IUserInterfaceFactory uiFactory; private IUserInterfaceFactory uiFactory;
public RuntimeController( public RuntimeController(
ILogger logger, ILogger logger,
IOperationSequence operationSequence, IOperationSequence bootstrapSequence,
IOperationSequence sessionSequence,
IRuntimeInfo runtimeInfo, IRuntimeInfo runtimeInfo,
IServiceProxy serviceProxy, IServiceProxy serviceProxy,
ISettingsRepository settingsRepository, ISettingsRepository settingsRepository,
@ -42,7 +44,8 @@ namespace SafeExamBrowser.Runtime.Behaviour
IUserInterfaceFactory uiFactory) IUserInterfaceFactory uiFactory)
{ {
this.logger = logger; this.logger = logger;
this.operationSequence = operationSequence; this.bootstrapSequence = bootstrapSequence;
this.sessionSequence = sessionSequence;
this.runtimeInfo = runtimeInfo; this.runtimeInfo = runtimeInfo;
this.serviceProxy = serviceProxy; this.serviceProxy = serviceProxy;
this.settingsRepository = settingsRepository; this.settingsRepository = settingsRepository;
@ -51,21 +54,30 @@ namespace SafeExamBrowser.Runtime.Behaviour
this.uiFactory = uiFactory; this.uiFactory = uiFactory;
} }
public bool TryStart(Queue<IOperation> operations) public bool TryStart()
{ {
logger.Info("--- Initiating startup procedure ---"); 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) if (success)
{ {
runtimeWindow = uiFactory.CreateRuntimeWindow(runtimeInfo, text);
logger.Info("--- Application successfully initialized! ---"); logger.Info("--- Application successfully initialized! ---");
logger.Log(string.Empty); logger.Log(string.Empty);
logger.Subscribe(runtimeWindow); logger.Subscribe(runtimeWindow);
StartSession(); splashScreen.Hide();
StartSession(true);
} }
else else
{ {
@ -76,33 +88,6 @@ namespace SafeExamBrowser.Runtime.Behaviour
return success; 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() public void Terminate()
{ {
StopSession(); StopSession();
@ -113,12 +98,13 @@ namespace SafeExamBrowser.Runtime.Behaviour
// - Revert kiosk mode (or do that when stopping session?) // - Revert kiosk mode (or do that when stopping session?)
logger.Unsubscribe(runtimeWindow); logger.Unsubscribe(runtimeWindow);
runtimeWindow.Close(); runtimeWindow?.Close();
splashScreen?.Show();
logger.Log(string.Empty); logger.Log(string.Empty);
logger.Info("--- Initiating shutdown procedure ---"); logger.Info("--- Initiating shutdown procedure ---");
var success = operationSequence.TryRevert(); var success = bootstrapSequence.TryRevert();
if (success) if (success)
{ {
@ -128,6 +114,48 @@ namespace SafeExamBrowser.Runtime.Behaviour
{ {
logger.Info("--- Shutdown procedure failed! ---"); 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() private void StopSession()
@ -135,7 +163,7 @@ namespace SafeExamBrowser.Runtime.Behaviour
logger.Info("Stopping current session..."); logger.Info("Stopping current session...");
runtimeWindow.Show(); runtimeWindow.Show();
runtimeWindow.BringToForeground(); runtimeWindow.BringToForeground();
runtimeWindow.UpdateStatus(TextKey.RuntimeWindow_StopSession, true); runtimeWindow.UpdateText(TextKey.RuntimeWindow_StopSession, true);
// TODO: // TODO:
// - Terminate client (or does it terminate itself?) // - Terminate client (or does it terminate itself?)

View file

@ -35,11 +35,12 @@ namespace SafeExamBrowser.Runtime
private ISystemInfo systemInfo; private ISystemInfo systemInfo;
internal IRuntimeController RuntimeController { get; private set; } internal IRuntimeController RuntimeController { get; private set; }
internal Queue<IOperation> StartupOperations { get; private set; }
internal void BuildObjectGraph() internal void BuildObjectGraph()
{ {
var args = Environment.GetCommandLineArgs(); var args = Environment.GetCommandLineArgs();
var bootstrapOperations = new Queue<IOperation>();
var sessionOperations = new Queue<IOperation>();
var nativeMethods = new NativeMethods(); var nativeMethods = new NativeMethods();
var settingsRepository = new SettingsRepository(); var settingsRepository = new SettingsRepository();
var uiFactory = new UserInterfaceFactory(); var uiFactory = new UserInterfaceFactory();
@ -52,16 +53,19 @@ namespace SafeExamBrowser.Runtime
InitializeLogging(); InitializeLogging();
var text = new Text(logger); 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"); 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<IOperation>(); sessionOperations.Enqueue(new ConfigurationOperation(logger, runtimeInfo, settingsRepository, text, uiFactory, args));
StartupOperations.Enqueue(new I18nOperation(logger, text)); sessionOperations.Enqueue(new ServiceOperation(logger, serviceProxy, settingsRepository, text));
StartupOperations.Enqueue(new ConfigurationOperation(logger, runtimeInfo, settingsRepository, text, uiFactory, args)); sessionOperations.Enqueue(new KioskModeOperation(logger, settingsRepository));
StartupOperations.Enqueue(new ServiceOperation(logger, serviceProxy, settingsRepository, text));
StartupOperations.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() internal void LogStartupInformation()

View file

@ -8,7 +8,7 @@
mc:Ignorable="d" Background="White" Foreground="White" Height="500" Width="750" WindowStyle="None" WindowStartupLocation="CenterScreen" 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"> Icon="./Images/SafeExamBrowser.ico" ResizeMode="NoResize" Title="Safe Exam Browser" Topmost="True">
<Grid> <Grid>
<Border x:Name="AnimatedBorder" Panel.ZIndex="10" BorderBrush="DodgerBlue" BorderThickness="5"> <Border x:Name="AnimatedBorder" Panel.ZIndex="10" BorderBrush="DodgerBlue" BorderThickness="5" Visibility="{Binding AnimatedBorderVisibility}">
<Border.Effect> <Border.Effect>
<BlurEffect Radius="10" /> <BlurEffect Radius="10" />
</Border.Effect> </Border.Effect>
@ -41,8 +41,11 @@
<Image Grid.Column="0" Grid.ColumnSpan="2" Margin="-25,0,0,0" Source="pack://application:,,,/SafeExamBrowser.UserInterface.Classic;component/Images/SplashScreen.png" /> <Image Grid.Column="0" Grid.ColumnSpan="2" Margin="-25,0,0,0" Source="pack://application:,,,/SafeExamBrowser.UserInterface.Classic;component/Images/SplashScreen.png" />
<TextBlock x:Name="InfoTextBlock" Grid.Column="1" Foreground="Gray" Margin="10,75,175,10" TextWrapping="Wrap" /> <TextBlock x:Name="InfoTextBlock" Grid.Column="1" Foreground="Gray" Margin="10,75,175,10" TextWrapping="Wrap" />
</Grid> </Grid>
<ProgressBar x:Name="ProgressBar" Grid.Row="1" IsIndeterminate="True" Background="WhiteSmoke" BorderThickness="0" Foreground="DodgerBlue" Visibility="Hidden" /> <ProgressBar x:Name="ProgressBar" Grid.Row="1" Background="WhiteSmoke" BorderThickness="0" Foreground="DodgerBlue"
<TextBlock x:Name="StatusTextBlock" Grid.Row="1" FontSize="12" FontWeight="Bold" Foreground="Black" HorizontalAlignment="Center" Text="{Binding Status}" VerticalAlignment="Center" /> IsIndeterminate="{Binding IsIndeterminate}" Maximum="{Binding MaxProgress}" Value="{Binding CurrentProgress}"
Visibility="{Binding ProgressBarVisibility}" />
<TextBlock x:Name="StatusTextBlock" Grid.Row="1" FontSize="12" FontWeight="Bold" Foreground="Black" HorizontalAlignment="Center"
Text="{Binding Status}" VerticalAlignment="Center" />
<Border Grid.Row="2" BorderBrush="DodgerBlue" BorderThickness="0,0.5,0,0"> <Border Grid.Row="2" BorderBrush="DodgerBlue" BorderThickness="0,0.5,0,0">
<ScrollViewer x:Name="LogScrollViewer" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" Margin="0,10,0,0"> <ScrollViewer x:Name="LogScrollViewer" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" Margin="0,10,0,0">
<ScrollViewer.Resources> <ScrollViewer.Resources>

View file

@ -9,7 +9,6 @@
using System; using System;
using System.Windows; using System.Windows;
using System.Windows.Documents; using System.Windows.Documents;
using System.Windows.Input;
using SafeExamBrowser.Contracts.Configuration; using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.I18n; using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.Logging;
@ -62,6 +61,11 @@ namespace SafeExamBrowser.UserInterface.Classic
Dispatcher.Invoke(base.Hide); Dispatcher.Invoke(base.Hide);
} }
public void HideProgressBar()
{
model.ProgressBarVisibility = Visibility.Hidden;
}
public void Notify(ILogContent content) public void Notify(ILogContent content)
{ {
Dispatcher.Invoke(() => 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() public new void Show()
{ {
Dispatcher.Invoke(base.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() private void InitializeRuntimeWindow()
{ {
Title = $"{runtimeInfo.ProgramTitle} - Version {runtimeInfo.ProgramVersion}"; Title = $"{runtimeInfo.ProgramTitle} - Version {runtimeInfo.ProgramVersion}";
@ -103,6 +131,8 @@ namespace SafeExamBrowser.UserInterface.Classic
InfoTextBlock.Inlines.Add(new Run(runtimeInfo.ProgramCopyright) { FontSize = 10 }); InfoTextBlock.Inlines.Add(new Run(runtimeInfo.ProgramCopyright) { FontSize = 10 });
model = new RuntimeWindowViewModel(); model = new RuntimeWindowViewModel();
AnimatedBorder.DataContext = model;
ProgressBar.DataContext = model;
StatusTextBlock.DataContext = model; StatusTextBlock.DataContext = model;
Closing += (o, args) => args.Cancel = !allowClose; Closing += (o, args) => args.Cancel = !allowClose;

View file

@ -118,8 +118,8 @@
<Compile Include="Utilities\XamlIconResource.cs" /> <Compile Include="Utilities\XamlIconResource.cs" />
<Compile Include="ViewModels\DateTimeViewModel.cs" /> <Compile Include="ViewModels\DateTimeViewModel.cs" />
<Compile Include="ViewModels\LogViewModel.cs" /> <Compile Include="ViewModels\LogViewModel.cs" />
<Compile Include="ViewModels\ProgressIndicatorViewModel.cs" />
<Compile Include="ViewModels\RuntimeWindowViewModel.cs" /> <Compile Include="ViewModels\RuntimeWindowViewModel.cs" />
<Compile Include="ViewModels\SplashScreenViewModel.cs" />
<Page Include="AboutWindow.xaml"> <Page Include="AboutWindow.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>

View file

@ -18,7 +18,7 @@ namespace SafeExamBrowser.UserInterface.Classic
public partial class SplashScreen : Window, ISplashScreen public partial class SplashScreen : Window, ISplashScreen
{ {
private bool allowClose; private bool allowClose;
private SplashScreenViewModel model = new SplashScreenViewModel(); private ProgressIndicatorViewModel model = new ProgressIndicatorViewModel();
private IRuntimeInfo runtimeInfo; private IRuntimeInfo runtimeInfo;
private IText text; private IText text;
private WindowClosingEventHandler closing; private WindowClosingEventHandler closing;
@ -77,11 +77,16 @@ namespace SafeExamBrowser.UserInterface.Classic
model.IsIndeterminate = true; model.IsIndeterminate = true;
} }
public void SetMaxProgress(int max) public void SetMaxValue(int max)
{ {
model.MaxProgress = max; model.MaxProgress = max;
} }
public void SetValue(int value)
{
model.CurrentProgress = value;
}
public void UpdateText(TextKey key, bool showBusyIndication = false) public void UpdateText(TextKey key, bool showBusyIndication = false)
{ {
model.StopBusyIndication(); model.StopBusyIndication();

View file

@ -11,7 +11,7 @@ using System.Timers;
namespace SafeExamBrowser.UserInterface.Classic.ViewModels namespace SafeExamBrowser.UserInterface.Classic.ViewModels
{ {
class SplashScreenViewModel : INotifyPropertyChanged internal class ProgressIndicatorViewModel : INotifyPropertyChanged
{ {
private int currentProgress; private int currentProgress;
private bool isIndeterminate; private bool isIndeterminate;
@ -73,7 +73,7 @@ namespace SafeExamBrowser.UserInterface.Classic.ViewModels
} }
} }
public void StartBusyIndication() public virtual void StartBusyIndication()
{ {
StopBusyIndication(); StopBusyIndication();
@ -87,12 +87,17 @@ namespace SafeExamBrowser.UserInterface.Classic.ViewModels
busyTimer.Start(); busyTimer.Start();
} }
public void StopBusyIndication() public virtual void StopBusyIndication()
{ {
busyTimer?.Stop(); busyTimer?.Stop();
busyTimer?.Close(); busyTimer?.Close();
} }
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private void BusyTimer_Elapsed(object sender, ElapsedEventArgs e) private void BusyTimer_Elapsed(object sender, ElapsedEventArgs e)
{ {
var next = Status ?? string.Empty; var next = Status ?? string.Empty;

View file

@ -6,65 +6,52 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
using System.ComponentModel; using System.Windows;
using System.Timers;
namespace SafeExamBrowser.UserInterface.Classic.ViewModels namespace SafeExamBrowser.UserInterface.Classic.ViewModels
{ {
internal class RuntimeWindowViewModel : INotifyPropertyChanged internal class RuntimeWindowViewModel : ProgressIndicatorViewModel
{ {
private string status; private Visibility animatedBorderVisibility, progressBarVisibility;
private Timer timer;
public event PropertyChangedEventHandler PropertyChanged; public Visibility AnimatedBorderVisibility
public string Status
{ {
get get
{ {
return status; return animatedBorderVisibility;
} }
set set
{ {
status = value; animatedBorderVisibility = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Status))); OnPropertyChanged(nameof(AnimatedBorderVisibility));
} }
} }
public void StartBusyIndication() public Visibility ProgressBarVisibility
{ {
StopBusyIndication(); get
timer = new Timer
{ {
AutoReset = true, return progressBarVisibility;
Interval = 750 }
}; set
{
timer.Elapsed += Timer_Elapsed; progressBarVisibility = value;
timer.Start(); OnPropertyChanged(nameof(ProgressBarVisibility));
}
} }
public void StopBusyIndication() public override void StartBusyIndication()
{ {
timer?.Stop(); base.StartBusyIndication();
timer?.Close();
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("...")) AnimatedBorderVisibility = Visibility.Visible;
{
next = Status.Substring(0, Status.Length - 3);
}
else
{
next += ".";
}
Status = next;
} }
} }
} }

View file

@ -77,11 +77,16 @@ namespace SafeExamBrowser.UserInterface.Windows10
model.IsIndeterminate = true; model.IsIndeterminate = true;
} }
public void SetMaxProgress(int max) public void SetMaxValue(int max)
{ {
model.MaxProgress = max; model.MaxProgress = max;
} }
public void SetValue(int value)
{
model.CurrentProgress = value;
}
public void UpdateText(TextKey key, bool showBusyIndication = false) public void UpdateText(TextKey key, bool showBusyIndication = false)
{ {
model.StopBusyIndication(); model.StopBusyIndication();