SEBWIN-219: Continued implementing kiosk operation and realized that further changes to startup/runtime/shutdown-mechanism are necessary...
This commit is contained in:
parent
b22093e6a2
commit
18b8f66300
30 changed files with 505 additions and 82 deletions
|
@ -15,6 +15,7 @@ namespace SafeExamBrowser.Configuration.Settings
|
||||||
internal class Settings : ISettings
|
internal class Settings : ISettings
|
||||||
{
|
{
|
||||||
public ConfigurationMode ConfigurationMode { get; set; }
|
public ConfigurationMode ConfigurationMode { get; set; }
|
||||||
|
public KioskMode KioskMode { get; set; }
|
||||||
public ServicePolicy ServicePolicy { get; set; }
|
public ServicePolicy ServicePolicy { get; set; }
|
||||||
|
|
||||||
public IBrowserSettings Browser { get; set; }
|
public IBrowserSettings Browser { get; set; }
|
||||||
|
|
|
@ -14,5 +14,10 @@ namespace SafeExamBrowser.Contracts.Behaviour
|
||||||
/// Reverts any changes performed during the startup or runtime and releases all used resources.
|
/// Reverts any changes performed during the startup or runtime and releases all used resources.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void FinalizeApplication();
|
void FinalizeApplication();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new session and starts performing the runtime logic / event handling.
|
||||||
|
/// </summary>
|
||||||
|
void StartSession();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,13 +25,18 @@ namespace SafeExamBrowser.Contracts.Configuration.Settings
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IKeyboardSettings Keyboard { get; }
|
IKeyboardSettings Keyboard { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The kiosk mode which determines how the computer is locked down.
|
||||||
|
/// </summary>
|
||||||
|
KioskMode KioskMode { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// All mouse-related settings.
|
/// All mouse-related settings.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IMouseSettings Mouse { get; }
|
IMouseSettings Mouse { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The active service policy.
|
/// The active policy for the service component.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ServicePolicy ServicePolicy { get; }
|
ServicePolicy ServicePolicy { get; }
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* 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/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Contracts.Configuration.Settings
|
||||||
|
{
|
||||||
|
public enum KioskMode
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// No kiosk mode - should only be used for testing / debugging.
|
||||||
|
/// </summary>
|
||||||
|
None,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new desktop and runs the client application on it, without modifying the default desktop.
|
||||||
|
/// </summary>
|
||||||
|
CreateNewDesktop,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Terminates the Windows explorer shell and runs the client application on the default desktop.
|
||||||
|
/// </summary>
|
||||||
|
DisableExplorerShell
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,16 +26,20 @@ namespace SafeExamBrowser.Contracts.I18n
|
||||||
Notification_AboutTooltip,
|
Notification_AboutTooltip,
|
||||||
Notification_LogTooltip,
|
Notification_LogTooltip,
|
||||||
RuntimeWindow_ApplicationRunning,
|
RuntimeWindow_ApplicationRunning,
|
||||||
|
RuntimeWindow_StartSession,
|
||||||
|
RuntimeWindow_StopSession,
|
||||||
SplashScreen_CloseServiceConnection,
|
SplashScreen_CloseServiceConnection,
|
||||||
SplashScreen_EmptyClipboard,
|
SplashScreen_EmptyClipboard,
|
||||||
SplashScreen_InitializeBrowser,
|
SplashScreen_InitializeBrowser,
|
||||||
SplashScreen_InitializeConfiguration,
|
SplashScreen_InitializeConfiguration,
|
||||||
|
SplashScreen_InitializeKioskMode,
|
||||||
SplashScreen_InitializeProcessMonitoring,
|
SplashScreen_InitializeProcessMonitoring,
|
||||||
SplashScreen_InitializeServiceConnection,
|
SplashScreen_InitializeServiceConnection,
|
||||||
SplashScreen_InitializeTaskbar,
|
SplashScreen_InitializeTaskbar,
|
||||||
SplashScreen_InitializeWindowMonitoring,
|
SplashScreen_InitializeWindowMonitoring,
|
||||||
SplashScreen_InitializeWorkingArea,
|
SplashScreen_InitializeWorkingArea,
|
||||||
SplashScreen_RestoreWorkingArea,
|
SplashScreen_RestoreWorkingArea,
|
||||||
|
SplashScreen_RevertKioskMode,
|
||||||
SplashScreen_ShutdownProcedure,
|
SplashScreen_ShutdownProcedure,
|
||||||
SplashScreen_StartEventHandling,
|
SplashScreen_StartEventHandling,
|
||||||
SplashScreen_StartKeyboardInterception,
|
SplashScreen_StartKeyboardInterception,
|
||||||
|
|
|
@ -81,6 +81,7 @@
|
||||||
<Compile Include="Behaviour\IStartupController.cs" />
|
<Compile Include="Behaviour\IStartupController.cs" />
|
||||||
<Compile Include="Configuration\Settings\ISettingsRepository.cs" />
|
<Compile Include="Configuration\Settings\ISettingsRepository.cs" />
|
||||||
<Compile Include="Configuration\Settings\ITaskbarSettings.cs" />
|
<Compile Include="Configuration\Settings\ITaskbarSettings.cs" />
|
||||||
|
<Compile Include="Configuration\Settings\KioskMode.cs" />
|
||||||
<Compile Include="Configuration\Settings\ServicePolicy.cs" />
|
<Compile Include="Configuration\Settings\ServicePolicy.cs" />
|
||||||
<Compile Include="I18n\IText.cs" />
|
<Compile Include="I18n\IText.cs" />
|
||||||
<Compile Include="I18n\TextKey.cs" />
|
<Compile Include="I18n\TextKey.cs" />
|
||||||
|
|
|
@ -7,15 +7,16 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using SafeExamBrowser.Contracts.I18n;
|
using SafeExamBrowser.Contracts.I18n;
|
||||||
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Contracts.UserInterface
|
namespace SafeExamBrowser.Contracts.UserInterface
|
||||||
{
|
{
|
||||||
public interface IRuntimeWindow : IWindow
|
public interface IRuntimeWindow : ILogObserver, IWindow
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the status text of the runtime window. If the busy flag is set,
|
/// 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.
|
/// the window will show an animation to indicate a long-running operation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void UpdateStatus(TextKey key);
|
void UpdateStatus(TextKey key, bool showBusyIndication = false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,18 +10,8 @@ using SafeExamBrowser.Contracts.I18n;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Contracts.UserInterface
|
namespace SafeExamBrowser.Contracts.UserInterface
|
||||||
{
|
{
|
||||||
public interface ISplashScreen
|
public interface ISplashScreen : IWindow
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Closes the splash screen on its own thread.
|
|
||||||
/// </summary>
|
|
||||||
void InvokeClose();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Shows the splash screen on its own thread.
|
|
||||||
/// </summary>
|
|
||||||
void InvokeShow();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the progress bar of the splash screen according to the specified amount.
|
/// Updates the progress bar of the splash screen according to the specified amount.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -51,6 +51,12 @@ namespace SafeExamBrowser.Contracts.UserInterface
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ISystemPowerSupplyControl CreatePowerSupplyControl();
|
ISystemPowerSupplyControl CreatePowerSupplyControl();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new runtime window which runs on its own thread.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
IRuntimeWindow CreateRuntimeWindow(IRuntimeInfo runtimeInfo, IText text);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new splash screen which runs on its own thread.
|
/// Creates a new splash screen which runs on its own thread.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -27,6 +27,11 @@ namespace SafeExamBrowser.Contracts.UserInterface
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void Close();
|
void Close();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hides the window.
|
||||||
|
/// </summary>
|
||||||
|
void Hide();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Shows the window to the user.
|
/// Shows the window to the user.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -72,7 +72,7 @@ namespace SafeExamBrowser.Core.Behaviour
|
||||||
splashScreen = uiFactory.CreateSplashScreen(runtimeInfo, text);
|
splashScreen = uiFactory.CreateSplashScreen(runtimeInfo, text);
|
||||||
splashScreen.SetIndeterminate();
|
splashScreen.SetIndeterminate();
|
||||||
splashScreen.UpdateText(TextKey.SplashScreen_ShutdownProcedure);
|
splashScreen.UpdateText(TextKey.SplashScreen_ShutdownProcedure);
|
||||||
splashScreen.InvokeShow();
|
splashScreen.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LogAndShowException(Exception e)
|
private void LogAndShowException(Exception e)
|
||||||
|
@ -92,7 +92,7 @@ namespace SafeExamBrowser.Core.Behaviour
|
||||||
logger.Info("--- Shutdown procedure failed! ---");
|
logger.Info("--- Shutdown procedure failed! ---");
|
||||||
}
|
}
|
||||||
|
|
||||||
splashScreen?.InvokeClose();
|
splashScreen?.Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,7 +117,7 @@ namespace SafeExamBrowser.Core.Behaviour
|
||||||
splashScreen = uiFactory.CreateSplashScreen(runtimeInfo, text);
|
splashScreen = uiFactory.CreateSplashScreen(runtimeInfo, text);
|
||||||
splashScreen.SetMaxProgress(operationCount);
|
splashScreen.SetMaxProgress(operationCount);
|
||||||
splashScreen.UpdateText(TextKey.SplashScreen_StartupProcedure);
|
splashScreen.UpdateText(TextKey.SplashScreen_StartupProcedure);
|
||||||
splashScreen.InvokeShow();
|
splashScreen.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LogAndShowException(Exception e)
|
private void LogAndShowException(Exception e)
|
||||||
|
@ -139,7 +139,7 @@ namespace SafeExamBrowser.Core.Behaviour
|
||||||
logger.Info("--- Startup procedure aborted! ---");
|
logger.Info("--- Startup procedure aborted! ---");
|
||||||
}
|
}
|
||||||
|
|
||||||
splashScreen?.InvokeClose();
|
splashScreen?.Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,12 @@
|
||||||
<Entry key="RuntimeWindow_ApplicationRunning">
|
<Entry key="RuntimeWindow_ApplicationRunning">
|
||||||
The application is running.
|
The application is running.
|
||||||
</Entry>
|
</Entry>
|
||||||
|
<Entry key="RuntimeWindow_StartSession">
|
||||||
|
Starting new session
|
||||||
|
</Entry>
|
||||||
|
<Entry key="RuntimeWindow_StopSession">
|
||||||
|
Stopping current session
|
||||||
|
</Entry>
|
||||||
<Entry key="SplashScreen_CloseServiceConnection">
|
<Entry key="SplashScreen_CloseServiceConnection">
|
||||||
Closing service connection
|
Closing service connection
|
||||||
</Entry>
|
</Entry>
|
||||||
|
@ -45,6 +51,9 @@
|
||||||
<Entry key="SplashScreen_InitializeConfiguration">
|
<Entry key="SplashScreen_InitializeConfiguration">
|
||||||
Initializing application configuration
|
Initializing application configuration
|
||||||
</Entry>
|
</Entry>
|
||||||
|
<Entry key="SplashScreen_InitializeKioskMode">
|
||||||
|
Initializing kiosk mode
|
||||||
|
</Entry>
|
||||||
<Entry key="SplashScreen_InitializeProcessMonitoring">
|
<Entry key="SplashScreen_InitializeProcessMonitoring">
|
||||||
Initializing process monitoring
|
Initializing process monitoring
|
||||||
</Entry>
|
</Entry>
|
||||||
|
@ -63,6 +72,9 @@
|
||||||
<Entry key="SplashScreen_RestoreWorkingArea">
|
<Entry key="SplashScreen_RestoreWorkingArea">
|
||||||
Restoring working area
|
Restoring working area
|
||||||
</Entry>
|
</Entry>
|
||||||
|
<Entry key="SplashScreen_RevertKioskMode">
|
||||||
|
Reverting kiosk mode
|
||||||
|
</Entry>
|
||||||
<Entry key="SplashScreen_ShutdownProcedure">
|
<Entry key="SplashScreen_ShutdownProcedure">
|
||||||
Initiating shutdown procedure
|
Initiating shutdown procedure
|
||||||
</Entry>
|
</Entry>
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
||||||
|
@ -56,6 +55,8 @@ namespace SafeExamBrowser.Runtime
|
||||||
{
|
{
|
||||||
base.OnStartup(e);
|
base.OnStartup(e);
|
||||||
|
|
||||||
|
ShutdownMode = ShutdownMode.OnExplicitShutdown;
|
||||||
|
|
||||||
instances.BuildObjectGraph();
|
instances.BuildObjectGraph();
|
||||||
instances.LogStartupInformation();
|
instances.LogStartupInformation();
|
||||||
|
|
||||||
|
@ -63,9 +64,7 @@ namespace SafeExamBrowser.Runtime
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
MainWindow = instances.RuntimeWindow;
|
instances.RuntimeController.StartSession();
|
||||||
MainWindow.Closing += MainWindow_Closing;
|
|
||||||
MainWindow.Show();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -75,15 +74,10 @@ namespace SafeExamBrowser.Runtime
|
||||||
|
|
||||||
protected override void OnExit(ExitEventArgs e)
|
protected override void OnExit(ExitEventArgs e)
|
||||||
{
|
{
|
||||||
|
instances.RuntimeController.FinalizeApplication();
|
||||||
instances.LogShutdownInformation();
|
instances.LogShutdownInformation();
|
||||||
|
|
||||||
base.OnExit(e);
|
base.OnExit(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MainWindow_Closing(object sender, CancelEventArgs e)
|
|
||||||
{
|
|
||||||
MainWindow.Hide();
|
|
||||||
instances.RuntimeController.FinalizeApplication();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,25 +6,79 @@
|
||||||
* 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;
|
|
||||||
using SafeExamBrowser.Contracts.Behaviour;
|
using SafeExamBrowser.Contracts.Behaviour;
|
||||||
|
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||||
|
using SafeExamBrowser.Contracts.I18n;
|
||||||
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
using SafeExamBrowser.Contracts.UserInterface;
|
using SafeExamBrowser.Contracts.UserInterface;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||||
{
|
{
|
||||||
internal class KioskModeOperation : IOperation
|
internal class KioskModeOperation : IOperation
|
||||||
{
|
{
|
||||||
|
private ILogger logger;
|
||||||
|
private ISettingsRepository settingsRepository;
|
||||||
|
private KioskMode kioskMode;
|
||||||
|
|
||||||
public bool AbortStartup { get; private set; }
|
public bool AbortStartup { get; private set; }
|
||||||
public ISplashScreen SplashScreen { private get; set; }
|
public ISplashScreen SplashScreen { private get; set; }
|
||||||
|
|
||||||
|
public KioskModeOperation(ILogger logger, ISettingsRepository settingsRepository)
|
||||||
|
{
|
||||||
|
this.logger = logger;
|
||||||
|
this.settingsRepository = settingsRepository;
|
||||||
|
}
|
||||||
|
|
||||||
public void Perform()
|
public void Perform()
|
||||||
{
|
{
|
||||||
// TODO
|
kioskMode = settingsRepository.Current.KioskMode;
|
||||||
|
|
||||||
|
logger.Info($"Initializing kiosk mode '{kioskMode}'...");
|
||||||
|
SplashScreen.UpdateText(TextKey.SplashScreen_InitializeKioskMode);
|
||||||
|
|
||||||
|
if (kioskMode == KioskMode.CreateNewDesktop)
|
||||||
|
{
|
||||||
|
CreateNewDesktop();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DisableExplorerShell();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Revert()
|
public void Revert()
|
||||||
{
|
{
|
||||||
// TODO
|
logger.Info($"Reverting kiosk mode '{kioskMode}'...");
|
||||||
|
SplashScreen.UpdateText(TextKey.SplashScreen_RevertKioskMode);
|
||||||
|
|
||||||
|
if (kioskMode == KioskMode.CreateNewDesktop)
|
||||||
|
{
|
||||||
|
CloseNewDesktop();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RestartExplorerShell();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateNewDesktop()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CloseNewDesktop()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DisableExplorerShell()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RestartExplorerShell()
|
||||||
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,12 @@
|
||||||
* 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;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using SafeExamBrowser.Contracts.Behaviour;
|
using SafeExamBrowser.Contracts.Behaviour;
|
||||||
using SafeExamBrowser.Contracts.Communication;
|
using SafeExamBrowser.Contracts.Communication;
|
||||||
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||||
using SafeExamBrowser.Contracts.I18n;
|
using SafeExamBrowser.Contracts.I18n;
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
|
@ -19,66 +21,107 @@ namespace SafeExamBrowser.Runtime.Behaviour
|
||||||
{
|
{
|
||||||
internal class RuntimeController : IRuntimeController
|
internal class RuntimeController : IRuntimeController
|
||||||
{
|
{
|
||||||
private ICommunication serviceProxy;
|
|
||||||
private Queue<IOperation> operations;
|
private Queue<IOperation> operations;
|
||||||
private ILogger logger;
|
private ILogger logger;
|
||||||
|
private IRuntimeInfo runtimeInfo;
|
||||||
private IRuntimeWindow runtimeWindow;
|
private IRuntimeWindow runtimeWindow;
|
||||||
|
private IServiceProxy serviceProxy;
|
||||||
private ISettingsRepository settingsRepository;
|
private ISettingsRepository settingsRepository;
|
||||||
private IShutdownController shutdownController;
|
private IShutdownController shutdownController;
|
||||||
private IStartupController startupController;
|
private IStartupController startupController;
|
||||||
|
private Action terminationCallback;
|
||||||
public ISettings Settings { private get; set; }
|
private IText text;
|
||||||
|
private IUserInterfaceFactory uiFactory;
|
||||||
|
|
||||||
public RuntimeController(
|
public RuntimeController(
|
||||||
ICommunication serviceProxy,
|
|
||||||
ILogger logger,
|
ILogger logger,
|
||||||
IRuntimeWindow runtimeWindow,
|
IRuntimeInfo runtimeInfo,
|
||||||
|
IServiceProxy serviceProxy,
|
||||||
ISettingsRepository settingsRepository,
|
ISettingsRepository settingsRepository,
|
||||||
IShutdownController shutdownController,
|
IShutdownController shutdownController,
|
||||||
IStartupController startupController)
|
IStartupController startupController,
|
||||||
|
Action terminationCallback,
|
||||||
|
IText text,
|
||||||
|
IUserInterfaceFactory uiFactory)
|
||||||
{
|
{
|
||||||
this.serviceProxy = serviceProxy;
|
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.runtimeWindow = runtimeWindow;
|
this.runtimeInfo = runtimeInfo;
|
||||||
|
this.serviceProxy = serviceProxy;
|
||||||
this.settingsRepository = settingsRepository;
|
this.settingsRepository = settingsRepository;
|
||||||
this.shutdownController = shutdownController;
|
this.shutdownController = shutdownController;
|
||||||
this.startupController = startupController;
|
this.startupController = startupController;
|
||||||
|
this.terminationCallback = terminationCallback;
|
||||||
|
this.text = text;
|
||||||
|
this.uiFactory = uiFactory;
|
||||||
|
|
||||||
operations = new Queue<IOperation>();
|
operations = new Queue<IOperation>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryInitializeApplication(Queue<IOperation> operations)
|
public bool TryInitializeApplication(Queue<IOperation> operations)
|
||||||
{
|
{
|
||||||
operations = new Queue<IOperation>(operations);
|
|
||||||
|
|
||||||
var success = startupController.TryInitializeApplication(operations);
|
var success = startupController.TryInitializeApplication(operations);
|
||||||
|
|
||||||
|
runtimeWindow = uiFactory.CreateRuntimeWindow(runtimeInfo, text);
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
Start();
|
this.operations = new Queue<IOperation>(operations);
|
||||||
|
logger.Subscribe(runtimeWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void FinalizeApplication()
|
public void FinalizeApplication()
|
||||||
{
|
{
|
||||||
Stop();
|
StopSession();
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// - Disconnect from service
|
||||||
|
// - Terminate runtime communication host
|
||||||
|
// - Revert kiosk mode (or do that when stopping session?)
|
||||||
|
|
||||||
|
logger.Unsubscribe(runtimeWindow);
|
||||||
|
runtimeWindow.Close();
|
||||||
shutdownController.FinalizeApplication(new Queue<IOperation>(operations.Reverse()));
|
shutdownController.FinalizeApplication(new Queue<IOperation>(operations.Reverse()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Start()
|
private void StopSession()
|
||||||
{
|
{
|
||||||
logger.Info("Starting event handling...");
|
logger.Info("Stopping current session...");
|
||||||
// TODO SplashScreen.UpdateText(TextKey.SplashScreen_StartEventHandling);
|
runtimeWindow.Show();
|
||||||
|
runtimeWindow.BringToForeground();
|
||||||
|
runtimeWindow.UpdateStatus(TextKey.RuntimeWindow_StopSession, true);
|
||||||
|
|
||||||
runtimeWindow.UpdateStatus(TextKey.RuntimeWindow_ApplicationRunning);
|
// TODO:
|
||||||
}
|
// - Terminate client (or does it terminate itself?)
|
||||||
|
// - Finalize session with service
|
||||||
private void Stop()
|
// - Stop event handling and close session
|
||||||
{
|
|
||||||
logger.Info("Stopping event handling...");
|
|
||||||
// TODO SplashScreen.UpdateText(TextKey.SplashScreen_StopEventHandling);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Windows;
|
||||||
using SafeExamBrowser.Configuration;
|
using SafeExamBrowser.Configuration;
|
||||||
using SafeExamBrowser.Configuration.Settings;
|
using SafeExamBrowser.Configuration.Settings;
|
||||||
using SafeExamBrowser.Contracts.Behaviour;
|
using SafeExamBrowser.Contracts.Behaviour;
|
||||||
|
@ -35,7 +36,6 @@ namespace SafeExamBrowser.Runtime
|
||||||
|
|
||||||
internal IRuntimeController RuntimeController { get; private set; }
|
internal IRuntimeController RuntimeController { get; private set; }
|
||||||
internal Queue<IOperation> StartupOperations { get; private set; }
|
internal Queue<IOperation> StartupOperations { get; private set; }
|
||||||
internal RuntimeWindow RuntimeWindow { get; private set; }
|
|
||||||
|
|
||||||
internal void BuildObjectGraph()
|
internal void BuildObjectGraph()
|
||||||
{
|
{
|
||||||
|
@ -56,16 +56,13 @@ namespace SafeExamBrowser.Runtime
|
||||||
var shutdownController = new ShutdownController(logger, runtimeInfo, text, uiFactory);
|
var shutdownController = new ShutdownController(logger, runtimeInfo, text, uiFactory);
|
||||||
var startupController = new StartupController(logger, runtimeInfo, systemInfo, text, uiFactory);
|
var startupController = new StartupController(logger, runtimeInfo, systemInfo, text, uiFactory);
|
||||||
|
|
||||||
RuntimeWindow = new RuntimeWindow(new DefaultLogFormatter(), runtimeInfo, text);
|
RuntimeController = new RuntimeController(new ModuleLogger(logger, typeof(RuntimeController)), runtimeInfo, serviceProxy, settingsRepository, shutdownController, startupController, Application.Current.Shutdown, text, uiFactory);
|
||||||
RuntimeController = new RuntimeController(serviceProxy, new ModuleLogger(logger, typeof(RuntimeController)), RuntimeWindow, settingsRepository, shutdownController, startupController);
|
|
||||||
|
|
||||||
logger.Subscribe(RuntimeWindow);
|
|
||||||
|
|
||||||
StartupOperations = new Queue<IOperation>();
|
StartupOperations = new Queue<IOperation>();
|
||||||
StartupOperations.Enqueue(new I18nOperation(logger, text));
|
StartupOperations.Enqueue(new I18nOperation(logger, text));
|
||||||
StartupOperations.Enqueue(new ConfigurationOperation(logger, runtimeInfo, settingsRepository, text, uiFactory, args));
|
StartupOperations.Enqueue(new ConfigurationOperation(logger, runtimeInfo, settingsRepository, text, uiFactory, args));
|
||||||
StartupOperations.Enqueue(new ServiceOperation(logger, serviceProxy, settingsRepository, text));
|
StartupOperations.Enqueue(new ServiceOperation(logger, serviceProxy, settingsRepository, text));
|
||||||
StartupOperations.Enqueue(new KioskModeOperation());
|
StartupOperations.Enqueue(new KioskModeOperation(logger, settingsRepository));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void LogStartupInformation()
|
internal void LogStartupInformation()
|
||||||
|
|
|
@ -55,12 +55,30 @@ namespace SafeExamBrowser.UserInterface.Classic
|
||||||
|
|
||||||
public void BringToForeground()
|
public void BringToForeground()
|
||||||
{
|
{
|
||||||
if (WindowState == WindowState.Minimized)
|
Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
WindowState = WindowState.Normal;
|
if (WindowState == WindowState.Minimized)
|
||||||
}
|
{
|
||||||
|
WindowState = WindowState.Normal;
|
||||||
|
}
|
||||||
|
|
||||||
Activate();
|
Activate();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public new void Close()
|
||||||
|
{
|
||||||
|
Dispatcher.Invoke(base.Close);
|
||||||
|
}
|
||||||
|
|
||||||
|
public new void Hide()
|
||||||
|
{
|
||||||
|
Dispatcher.Invoke(base.Hide);
|
||||||
|
}
|
||||||
|
|
||||||
|
public new void Show()
|
||||||
|
{
|
||||||
|
Dispatcher.Invoke(base.Show);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateAddress(string url)
|
public void UpdateAddress(string url)
|
||||||
|
|
|
@ -47,6 +47,11 @@ namespace SafeExamBrowser.UserInterface.Classic
|
||||||
Dispatcher.Invoke(base.Close);
|
Dispatcher.Invoke(base.Close);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public new void Hide()
|
||||||
|
{
|
||||||
|
Dispatcher.Invoke(base.Hide);
|
||||||
|
}
|
||||||
|
|
||||||
public new void Show()
|
public new void Show()
|
||||||
{
|
{
|
||||||
Dispatcher.Invoke(base.Show);
|
Dispatcher.Invoke(base.Show);
|
||||||
|
|
|
@ -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 Panel.ZIndex="10" BorderBrush="DodgerBlue" BorderThickness="5">
|
<Border x:Name="AnimatedBorder" Panel.ZIndex="10" BorderBrush="DodgerBlue" BorderThickness="5">
|
||||||
<Border.Effect>
|
<Border.Effect>
|
||||||
<BlurEffect Radius="10" />
|
<BlurEffect Radius="10" />
|
||||||
</Border.Effect>
|
</Border.Effect>
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
|
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
|
||||||
<BeginStoryboard>
|
<BeginStoryboard>
|
||||||
<Storyboard>
|
<Storyboard>
|
||||||
<DoubleAnimation AutoReverse="True" Storyboard.TargetProperty="Opacity" From="1.0" To="0.2" Duration="0:0:2.5" RepeatBehavior="Forever" />
|
<DoubleAnimation AutoReverse="True" Storyboard.TargetProperty="Opacity" From="0.2" To="1.0" Duration="0:0:2.5" RepeatBehavior="Forever" />
|
||||||
</Storyboard>
|
</Storyboard>
|
||||||
</BeginStoryboard>
|
</BeginStoryboard>
|
||||||
</EventTrigger>
|
</EventTrigger>
|
||||||
|
@ -41,8 +41,8 @@
|
||||||
<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" BorderThickness="0" />-->
|
<ProgressBar x:Name="ProgressBar" Grid.Row="1" IsIndeterminate="True" Background="WhiteSmoke" BorderThickness="0" Foreground="DodgerBlue" Visibility="Hidden" />
|
||||||
<TextBlock x:Name="StatusTextBlock" Grid.Row="1" Text="Application is running..." FontSize="12" FontWeight="Bold" Foreground="Black" HorizontalAlignment="Center" VerticalAlignment="Center" />
|
<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>
|
||||||
|
|
|
@ -9,18 +9,22 @@
|
||||||
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;
|
||||||
using SafeExamBrowser.Contracts.UserInterface;
|
using SafeExamBrowser.Contracts.UserInterface;
|
||||||
|
using SafeExamBrowser.UserInterface.Classic.ViewModels;
|
||||||
|
|
||||||
namespace SafeExamBrowser.UserInterface.Classic
|
namespace SafeExamBrowser.UserInterface.Classic
|
||||||
{
|
{
|
||||||
public partial class RuntimeWindow : Window, ILogObserver, IRuntimeWindow
|
public partial class RuntimeWindow : Window, IRuntimeWindow
|
||||||
{
|
{
|
||||||
|
private bool allowClose;
|
||||||
private ILogContentFormatter formatter;
|
private ILogContentFormatter formatter;
|
||||||
private IRuntimeInfo runtimeInfo;
|
private IRuntimeInfo runtimeInfo;
|
||||||
private IText text;
|
private IText text;
|
||||||
|
private RuntimeWindowViewModel model;
|
||||||
private WindowClosingEventHandler closing;
|
private WindowClosingEventHandler closing;
|
||||||
|
|
||||||
event WindowClosingEventHandler IWindow.Closing
|
event WindowClosingEventHandler IWindow.Closing
|
||||||
|
@ -44,6 +48,20 @@ namespace SafeExamBrowser.UserInterface.Classic
|
||||||
Dispatcher.Invoke(Activate);
|
Dispatcher.Invoke(Activate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public new void Close()
|
||||||
|
{
|
||||||
|
Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
allowClose = true;
|
||||||
|
base.Close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public new void Hide()
|
||||||
|
{
|
||||||
|
Dispatcher.Invoke(base.Hide);
|
||||||
|
}
|
||||||
|
|
||||||
public void Notify(ILogContent content)
|
public void Notify(ILogContent content)
|
||||||
{
|
{
|
||||||
Dispatcher.Invoke(() =>
|
Dispatcher.Invoke(() =>
|
||||||
|
@ -53,18 +71,41 @@ namespace SafeExamBrowser.UserInterface.Classic
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateStatus(TextKey key)
|
public new void Show()
|
||||||
{
|
{
|
||||||
Dispatcher.Invoke(() => StatusTextBlock.Text = text.Get(key));
|
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}";
|
||||||
|
|
||||||
InfoTextBlock.Inlines.Add(new Run($"Version {runtimeInfo.ProgramVersion}") { FontStyle = FontStyles.Italic });
|
InfoTextBlock.Inlines.Add(new Run($"Version {runtimeInfo.ProgramVersion}") { FontStyle = FontStyles.Italic });
|
||||||
InfoTextBlock.Inlines.Add(new LineBreak());
|
InfoTextBlock.Inlines.Add(new LineBreak());
|
||||||
InfoTextBlock.Inlines.Add(new LineBreak());
|
InfoTextBlock.Inlines.Add(new LineBreak());
|
||||||
InfoTextBlock.Inlines.Add(new Run(runtimeInfo.ProgramCopyright) { FontSize = 10 });
|
InfoTextBlock.Inlines.Add(new Run(runtimeInfo.ProgramCopyright) { FontSize = 10 });
|
||||||
|
|
||||||
|
model = new RuntimeWindowViewModel();
|
||||||
|
StatusTextBlock.DataContext = model;
|
||||||
|
|
||||||
|
Closing += (o, args) => args.Cancel = !allowClose;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,10 +113,12 @@
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="UserInterfaceFactory.cs" />
|
<Compile Include="UserInterfaceFactory.cs" />
|
||||||
<Compile Include="Utilities\IconResourceLoader.cs" />
|
<Compile Include="Utilities\IconResourceLoader.cs" />
|
||||||
|
<Compile Include="Utilities\RuntimeWindowLogFormatter.cs" />
|
||||||
<Compile Include="Utilities\VisualExtensions.cs" />
|
<Compile Include="Utilities\VisualExtensions.cs" />
|
||||||
<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\RuntimeWindowViewModel.cs" />
|
||||||
<Compile Include="ViewModels\SplashScreenViewModel.cs" />
|
<Compile Include="ViewModels\SplashScreenViewModel.cs" />
|
||||||
<Page Include="AboutWindow.xaml">
|
<Page Include="AboutWindow.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
|
|
|
@ -17,9 +17,17 @@ namespace SafeExamBrowser.UserInterface.Classic
|
||||||
{
|
{
|
||||||
public partial class SplashScreen : Window, ISplashScreen
|
public partial class SplashScreen : Window, ISplashScreen
|
||||||
{
|
{
|
||||||
|
private bool allowClose;
|
||||||
private SplashScreenViewModel model = new SplashScreenViewModel();
|
private SplashScreenViewModel model = new SplashScreenViewModel();
|
||||||
private IRuntimeInfo runtimeInfo;
|
private IRuntimeInfo runtimeInfo;
|
||||||
private IText text;
|
private IText text;
|
||||||
|
private WindowClosingEventHandler closing;
|
||||||
|
|
||||||
|
event WindowClosingEventHandler IWindow.Closing
|
||||||
|
{
|
||||||
|
add { closing += value; }
|
||||||
|
remove { closing -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
public SplashScreen(IRuntimeInfo runtimeInfo, IText text)
|
public SplashScreen(IRuntimeInfo runtimeInfo, IText text)
|
||||||
{
|
{
|
||||||
|
@ -30,14 +38,28 @@ namespace SafeExamBrowser.UserInterface.Classic
|
||||||
InitializeSplashScreen();
|
InitializeSplashScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InvokeClose()
|
public void BringToForeground()
|
||||||
{
|
{
|
||||||
Dispatcher.Invoke(Close);
|
Dispatcher.Invoke(Activate);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InvokeShow()
|
public new void Close()
|
||||||
{
|
{
|
||||||
Dispatcher.Invoke(Show);
|
Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
allowClose = true;
|
||||||
|
base.Close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public new void Hide()
|
||||||
|
{
|
||||||
|
Dispatcher.Invoke(base.Hide);
|
||||||
|
}
|
||||||
|
|
||||||
|
public new void Show()
|
||||||
|
{
|
||||||
|
Dispatcher.Invoke(base.Show);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Progress(int amount = 1)
|
public void Progress(int amount = 1)
|
||||||
|
@ -83,6 +105,8 @@ namespace SafeExamBrowser.UserInterface.Classic
|
||||||
|
|
||||||
// To prevent the progress bar going from max to min value at startup...
|
// To prevent the progress bar going from max to min value at startup...
|
||||||
model.MaxProgress = 1;
|
model.MaxProgress = 1;
|
||||||
|
|
||||||
|
Closing += (o, args) => args.Cancel = !allowClose;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ using SafeExamBrowser.Contracts.Logging;
|
||||||
using SafeExamBrowser.Contracts.UserInterface;
|
using SafeExamBrowser.Contracts.UserInterface;
|
||||||
using SafeExamBrowser.Contracts.UserInterface.Taskbar;
|
using SafeExamBrowser.Contracts.UserInterface.Taskbar;
|
||||||
using SafeExamBrowser.UserInterface.Classic.Controls;
|
using SafeExamBrowser.UserInterface.Classic.Controls;
|
||||||
|
using SafeExamBrowser.UserInterface.Classic.Utilities;
|
||||||
using MessageBoxResult = SafeExamBrowser.Contracts.UserInterface.MessageBoxResult;
|
using MessageBoxResult = SafeExamBrowser.Contracts.UserInterface.MessageBoxResult;
|
||||||
|
|
||||||
namespace SafeExamBrowser.UserInterface.Classic
|
namespace SafeExamBrowser.UserInterface.Classic
|
||||||
|
@ -76,6 +77,30 @@ namespace SafeExamBrowser.UserInterface.Classic
|
||||||
return new PowerSupplyControl();
|
return new PowerSupplyControl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IRuntimeWindow CreateRuntimeWindow(IRuntimeInfo runtimeInfo, IText text)
|
||||||
|
{
|
||||||
|
RuntimeWindow runtimeWindow = null;
|
||||||
|
var windowReadyEvent = new AutoResetEvent(false);
|
||||||
|
var runtimeWindowThread = new Thread(() =>
|
||||||
|
{
|
||||||
|
runtimeWindow = new RuntimeWindow(new RuntimeWindowLogFormatter(), runtimeInfo, text);
|
||||||
|
runtimeWindow.Closed += (o, args) => runtimeWindow.Dispatcher.InvokeShutdown();
|
||||||
|
|
||||||
|
windowReadyEvent.Set();
|
||||||
|
|
||||||
|
System.Windows.Threading.Dispatcher.Run();
|
||||||
|
});
|
||||||
|
|
||||||
|
runtimeWindowThread.SetApartmentState(ApartmentState.STA);
|
||||||
|
runtimeWindowThread.Name = nameof(RuntimeWindow);
|
||||||
|
runtimeWindowThread.IsBackground = true;
|
||||||
|
runtimeWindowThread.Start();
|
||||||
|
|
||||||
|
windowReadyEvent.WaitOne();
|
||||||
|
|
||||||
|
return runtimeWindow;
|
||||||
|
}
|
||||||
|
|
||||||
public ISplashScreen CreateSplashScreen(IRuntimeInfo runtimeInfo, IText text)
|
public ISplashScreen CreateSplashScreen(IRuntimeInfo runtimeInfo, IText text)
|
||||||
{
|
{
|
||||||
SplashScreen splashScreen = null;
|
SplashScreen splashScreen = null;
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* 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 System;
|
||||||
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.UserInterface.Classic.Utilities
|
||||||
|
{
|
||||||
|
internal class RuntimeWindowLogFormatter : ILogContentFormatter
|
||||||
|
{
|
||||||
|
public string Format(ILogContent content)
|
||||||
|
{
|
||||||
|
if (content is ILogText)
|
||||||
|
{
|
||||||
|
return (content as ILogText).Text;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (content is ILogMessage)
|
||||||
|
{
|
||||||
|
return FormatLogMessage(content as ILogMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotImplementedException($"The runtime window formatter is not yet implemented for log content of type {content.GetType()}!");
|
||||||
|
}
|
||||||
|
|
||||||
|
private string FormatLogMessage(ILogMessage message)
|
||||||
|
{
|
||||||
|
var time = message.DateTime.ToString("HH:mm:ss.fff");
|
||||||
|
var severity = message.Severity.ToString().ToUpper();
|
||||||
|
|
||||||
|
return $"{time} - {severity}: {message.Message}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
* 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 System.ComponentModel;
|
||||||
|
using System.Timers;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.UserInterface.Classic.ViewModels
|
||||||
|
{
|
||||||
|
internal class RuntimeWindowViewModel : INotifyPropertyChanged
|
||||||
|
{
|
||||||
|
private string status;
|
||||||
|
private Timer timer;
|
||||||
|
|
||||||
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
|
public string Status
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
status = value;
|
||||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Status)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartBusyIndication()
|
||||||
|
{
|
||||||
|
StopBusyIndication();
|
||||||
|
|
||||||
|
timer = new Timer
|
||||||
|
{
|
||||||
|
AutoReset = true,
|
||||||
|
Interval = 750
|
||||||
|
};
|
||||||
|
|
||||||
|
timer.Elapsed += Timer_Elapsed;
|
||||||
|
timer.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StopBusyIndication()
|
||||||
|
{
|
||||||
|
timer?.Stop();
|
||||||
|
timer?.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
|
||||||
|
{
|
||||||
|
var next = Status ?? string.Empty;
|
||||||
|
|
||||||
|
if (next.EndsWith("..."))
|
||||||
|
{
|
||||||
|
next = Status.Substring(0, Status.Length - 3);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
next += ".";
|
||||||
|
}
|
||||||
|
|
||||||
|
Status = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -53,12 +53,30 @@ namespace SafeExamBrowser.UserInterface.Windows10
|
||||||
|
|
||||||
public void BringToForeground()
|
public void BringToForeground()
|
||||||
{
|
{
|
||||||
if (WindowState == WindowState.Minimized)
|
Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
WindowState = WindowState.Normal;
|
if (WindowState == WindowState.Minimized)
|
||||||
}
|
{
|
||||||
|
WindowState = WindowState.Normal;
|
||||||
|
}
|
||||||
|
|
||||||
Activate();
|
Activate();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public new void Close()
|
||||||
|
{
|
||||||
|
Dispatcher.Invoke(base.Close);
|
||||||
|
}
|
||||||
|
|
||||||
|
public new void Hide()
|
||||||
|
{
|
||||||
|
Dispatcher.Invoke(base.Hide);
|
||||||
|
}
|
||||||
|
|
||||||
|
public new void Show()
|
||||||
|
{
|
||||||
|
Dispatcher.Invoke(base.Show);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateAddress(string url)
|
public void UpdateAddress(string url)
|
||||||
|
|
|
@ -47,6 +47,11 @@ namespace SafeExamBrowser.UserInterface.Windows10
|
||||||
Dispatcher.Invoke(base.Close);
|
Dispatcher.Invoke(base.Close);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public new void Hide()
|
||||||
|
{
|
||||||
|
Dispatcher.Invoke(base.Hide);
|
||||||
|
}
|
||||||
|
|
||||||
public new void Show()
|
public new void Show()
|
||||||
{
|
{
|
||||||
Dispatcher.Invoke(base.Show);
|
Dispatcher.Invoke(base.Show);
|
||||||
|
|
|
@ -17,9 +17,17 @@ namespace SafeExamBrowser.UserInterface.Windows10
|
||||||
{
|
{
|
||||||
public partial class SplashScreen : Window, ISplashScreen
|
public partial class SplashScreen : Window, ISplashScreen
|
||||||
{
|
{
|
||||||
|
private bool allowClose;
|
||||||
private SplashScreenViewModel model = new SplashScreenViewModel();
|
private SplashScreenViewModel model = new SplashScreenViewModel();
|
||||||
private IRuntimeInfo runtimeInfo;
|
private IRuntimeInfo runtimeInfo;
|
||||||
private IText text;
|
private IText text;
|
||||||
|
private WindowClosingEventHandler closing;
|
||||||
|
|
||||||
|
event WindowClosingEventHandler IWindow.Closing
|
||||||
|
{
|
||||||
|
add { closing += value; }
|
||||||
|
remove { closing -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
public SplashScreen(IRuntimeInfo runtimeInfo, IText text)
|
public SplashScreen(IRuntimeInfo runtimeInfo, IText text)
|
||||||
{
|
{
|
||||||
|
@ -30,14 +38,28 @@ namespace SafeExamBrowser.UserInterface.Windows10
|
||||||
InitializeSplashScreen();
|
InitializeSplashScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InvokeClose()
|
public void BringToForeground()
|
||||||
{
|
{
|
||||||
Dispatcher.Invoke(Close);
|
Dispatcher.Invoke(Activate);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InvokeShow()
|
public new void Close()
|
||||||
{
|
{
|
||||||
Dispatcher.Invoke(Show);
|
Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
allowClose = true;
|
||||||
|
base.Close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public new void Hide()
|
||||||
|
{
|
||||||
|
Dispatcher.Invoke(base.Hide);
|
||||||
|
}
|
||||||
|
|
||||||
|
public new void Show()
|
||||||
|
{
|
||||||
|
Dispatcher.Invoke(base.Show);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Progress(int amount = 1)
|
public void Progress(int amount = 1)
|
||||||
|
@ -83,6 +105,8 @@ namespace SafeExamBrowser.UserInterface.Windows10
|
||||||
|
|
||||||
// To prevent the progress bar going from max to min value at startup...
|
// To prevent the progress bar going from max to min value at startup...
|
||||||
model.MaxProgress = 1;
|
model.MaxProgress = 1;
|
||||||
|
|
||||||
|
Closing += (o, args) => args.Cancel = !allowClose;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,6 +77,12 @@ namespace SafeExamBrowser.UserInterface.Windows10
|
||||||
return new PowerSupplyControl();
|
return new PowerSupplyControl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IRuntimeWindow CreateRuntimeWindow(IRuntimeInfo runtimeInfo, IText text)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
public ISplashScreen CreateSplashScreen(IRuntimeInfo runtimeInfo, IText text)
|
public ISplashScreen CreateSplashScreen(IRuntimeInfo runtimeInfo, IText text)
|
||||||
{
|
{
|
||||||
SplashScreen splashScreen = null;
|
SplashScreen splashScreen = null;
|
||||||
|
|
Loading…
Reference in a new issue