Enhanced startup- and shutdown-procedure by introducing a stack of IOperations (which are automatically reverted on shutdown or if an error happens during startup).
This commit is contained in:
parent
eb6fbf49b8
commit
1153fea091
18 changed files with 429 additions and 167 deletions
|
@ -18,7 +18,7 @@ namespace SafeExamBrowser.Configuration
|
|||
public class WorkingArea : IWorkingArea
|
||||
{
|
||||
private ILogger logger;
|
||||
private RECT? initial;
|
||||
private RECT? originalWorkingArea;
|
||||
|
||||
public WorkingArea(ILogger logger)
|
||||
{
|
||||
|
@ -27,9 +27,9 @@ namespace SafeExamBrowser.Configuration
|
|||
|
||||
public void InitializeFor(ITaskbar taskbar)
|
||||
{
|
||||
initial = User32.GetWorkingArea();
|
||||
originalWorkingArea = User32.GetWorkingArea();
|
||||
|
||||
LogWorkingArea("Saved initial working area", initial.Value);
|
||||
LogWorkingArea("Saved original working area", originalWorkingArea.Value);
|
||||
|
||||
var area = new RECT
|
||||
{
|
||||
|
@ -39,17 +39,17 @@ namespace SafeExamBrowser.Configuration
|
|||
Bottom = Screen.PrimaryScreen.Bounds.Height - taskbar.GetAbsoluteHeight()
|
||||
};
|
||||
|
||||
LogWorkingArea("Setting new working area", area);
|
||||
LogWorkingArea("Trying to set new working area", area);
|
||||
User32.SetWorkingArea(area);
|
||||
LogWorkingArea("Working area is now set to", User32.GetWorkingArea());
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
if (initial.HasValue)
|
||||
if (originalWorkingArea.HasValue)
|
||||
{
|
||||
User32.SetWorkingArea(initial.Value);
|
||||
LogWorkingArea("Restored initial working area", initial.Value);
|
||||
User32.SetWorkingArea(originalWorkingArea.Value);
|
||||
LogWorkingArea("Restored original working area", originalWorkingArea.Value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
30
SafeExamBrowser.Contracts/Behaviour/IOperation.cs
Normal file
30
SafeExamBrowser.Contracts/Behaviour/IOperation.cs
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2017 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Behaviour
|
||||
{
|
||||
public interface IOperation
|
||||
{
|
||||
/// <summary>
|
||||
/// The splash screen to be used to show status information to the user.
|
||||
/// </summary>
|
||||
ISplashScreen SplashScreen { set; }
|
||||
|
||||
/// <summary>
|
||||
/// Performs the operation.
|
||||
/// </summary>
|
||||
void Perform();
|
||||
|
||||
/// <summary>
|
||||
/// Reverts all changes which were made when performing the operation.
|
||||
/// </summary>
|
||||
void Revert();
|
||||
}
|
||||
}
|
|
@ -6,6 +6,8 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Behaviour
|
||||
{
|
||||
public interface IShutdownController
|
||||
|
@ -13,6 +15,6 @@ namespace SafeExamBrowser.Contracts.Behaviour
|
|||
/// <summary>
|
||||
/// Reverts any changes performed during the startup or runtime and releases all used resources.
|
||||
/// </summary>
|
||||
void FinalizeApplication();
|
||||
void FinalizeApplication(Stack<IOperation> operations);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,14 +6,17 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Behaviour
|
||||
{
|
||||
public interface IStartupController
|
||||
{
|
||||
/// <summary>
|
||||
/// Tries to initialize the application. Returns <c>true</c> if the initialization was successful,
|
||||
/// <c>false</c> otherwise.
|
||||
/// <c>false</c> otherwise. All operations performed during the startup procedure will be registered
|
||||
/// to the given <c>out</c> parameter.
|
||||
/// </summary>
|
||||
bool TryInitializeApplication();
|
||||
bool TryInitializeApplication(out Stack<IOperation> operations);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
<ItemGroup>
|
||||
<Compile Include="Behaviour\IApplicationController.cs" />
|
||||
<Compile Include="Behaviour\INotificationController.cs" />
|
||||
<Compile Include="Behaviour\IOperation.cs" />
|
||||
<Compile Include="Configuration\IIconResource.cs" />
|
||||
<Compile Include="Configuration\IApplicationInfo.cs" />
|
||||
<Compile Include="Configuration\IApplicationInstance.cs" />
|
||||
|
|
|
@ -22,16 +22,27 @@ namespace SafeExamBrowser.Contracts.UserInterface
|
|||
/// </summary>
|
||||
void InvokeShow();
|
||||
|
||||
/// <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 progress bar of the splash screen according to the specified amount.
|
||||
/// </summary>
|
||||
void UpdateProgress(int amount = 1);
|
||||
|
||||
/// <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.
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (c) 2017 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using SafeExamBrowser.Contracts.Behaviour;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
|
||||
namespace SafeExamBrowser.Core.Behaviour.Operations
|
||||
{
|
||||
class BrowserInitializationOperation : IOperation
|
||||
{
|
||||
private IApplicationController browserController;
|
||||
private IApplicationInfo browserInfo;
|
||||
private ILogger logger;
|
||||
private ITaskbar taskbar;
|
||||
private IUiElementFactory uiFactory;
|
||||
|
||||
public ISplashScreen SplashScreen { private get; set; }
|
||||
|
||||
public BrowserInitializationOperation(
|
||||
IApplicationController browserController,
|
||||
IApplicationInfo browserInfo,
|
||||
ILogger logger,
|
||||
ITaskbar taskbar,
|
||||
IUiElementFactory uiFactory)
|
||||
{
|
||||
this.browserController = browserController;
|
||||
this.browserInfo = browserInfo;
|
||||
this.logger = logger;
|
||||
this.taskbar = taskbar;
|
||||
this.uiFactory = uiFactory;
|
||||
}
|
||||
|
||||
public void Perform()
|
||||
{
|
||||
logger.Info("--- Initializing browser ---");
|
||||
SplashScreen.UpdateText(Key.SplashScreen_InitializeBrowser);
|
||||
|
||||
var browserButton = uiFactory.CreateApplicationButton(browserInfo);
|
||||
|
||||
browserController.RegisterApplicationButton(browserButton);
|
||||
taskbar.AddButton(browserButton);
|
||||
}
|
||||
|
||||
public void Revert()
|
||||
{
|
||||
// Nothing to do here so far...
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2017 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using SafeExamBrowser.Contracts.Behaviour;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.Monitoring;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
|
||||
namespace SafeExamBrowser.Core.Behaviour.Operations
|
||||
{
|
||||
class ProcessMonitoringOperation : IOperation
|
||||
{
|
||||
private ILogger logger;
|
||||
private IProcessMonitor processMonitor;
|
||||
|
||||
public ISplashScreen SplashScreen { private get; set; }
|
||||
|
||||
public ProcessMonitoringOperation(ILogger logger, IProcessMonitor processMonitor)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.processMonitor = processMonitor;
|
||||
}
|
||||
|
||||
public void Perform()
|
||||
{
|
||||
logger.Info("--- Initializing process monitoring ---");
|
||||
SplashScreen.UpdateText(Key.SplashScreen_InitializeProcessMonitoring);
|
||||
|
||||
// TODO
|
||||
}
|
||||
|
||||
public void Revert()
|
||||
{
|
||||
logger.Info("--- Stopping process monitoring ---");
|
||||
SplashScreen.UpdateText(Key.SplashScreen_StopProcessMonitoring);
|
||||
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2017 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using SafeExamBrowser.Contracts.Behaviour;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
|
||||
namespace SafeExamBrowser.Core.Behaviour.Operations
|
||||
{
|
||||
class TaskbarInitializationOperation : IOperation
|
||||
{
|
||||
private ILogger logger;
|
||||
private ITaskbar taskbar;
|
||||
private IUiElementFactory uiFactory;
|
||||
private INotificationInfo aboutInfo;
|
||||
|
||||
public ISplashScreen SplashScreen { private get; set; }
|
||||
|
||||
public TaskbarInitializationOperation(ILogger logger, INotificationInfo aboutInfo, ITaskbar taskbar, IUiElementFactory uiFactory)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.aboutInfo = aboutInfo;
|
||||
this.taskbar = taskbar;
|
||||
this.uiFactory = uiFactory;
|
||||
}
|
||||
|
||||
public void Perform()
|
||||
{
|
||||
logger.Info("--- Initializing taskbar ---");
|
||||
SplashScreen.UpdateText(Key.SplashScreen_InitializeTaskbar);
|
||||
|
||||
var aboutNotification = uiFactory.CreateNotification(aboutInfo);
|
||||
|
||||
taskbar.AddNotification(aboutNotification);
|
||||
}
|
||||
|
||||
public void Revert()
|
||||
{
|
||||
// Nothing to do here so far...
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright (c) 2017 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using SafeExamBrowser.Contracts.Behaviour;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.Monitoring;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
|
||||
namespace SafeExamBrowser.Core.Behaviour.Operations
|
||||
{
|
||||
class WorkingAreaOperation : IOperation
|
||||
{
|
||||
private ILogger logger;
|
||||
private IProcessMonitor processMonitor;
|
||||
private ITaskbar taskbar;
|
||||
private IWorkingArea workingArea;
|
||||
|
||||
public ISplashScreen SplashScreen { private get; set; }
|
||||
|
||||
public WorkingAreaOperation(ILogger logger, IProcessMonitor processMonitor, ITaskbar taskbar, IWorkingArea workingArea)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.processMonitor = processMonitor;
|
||||
this.taskbar = taskbar;
|
||||
this.workingArea = workingArea;
|
||||
}
|
||||
|
||||
public void Perform()
|
||||
{
|
||||
logger.Info("--- Initializing working area ---");
|
||||
SplashScreen.UpdateText(Key.SplashScreen_WaitExplorerTermination, true);
|
||||
|
||||
processMonitor.CloseExplorerShell();
|
||||
processMonitor.StartMonitoringExplorer();
|
||||
|
||||
// TODO
|
||||
// - Minimizing all open windows
|
||||
// - Emptying clipboard
|
||||
|
||||
SplashScreen.UpdateText(Key.SplashScreen_InitializeWorkingArea);
|
||||
workingArea.InitializeFor(taskbar);
|
||||
}
|
||||
|
||||
public void Revert()
|
||||
{
|
||||
logger.Info("--- Restoring working area ---");
|
||||
SplashScreen.UpdateText(Key.SplashScreen_RestoreWorkingArea);
|
||||
|
||||
// TODO
|
||||
// - Restore all windows?
|
||||
// - Emptying clipboard
|
||||
|
||||
workingArea.Reset();
|
||||
|
||||
SplashScreen.UpdateText(Key.SplashScreen_WaitExplorerStartup, true);
|
||||
|
||||
processMonitor.StopMonitoringExplorer();
|
||||
processMonitor.StartExplorerShell();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -30,16 +30,6 @@ namespace SafeExamBrowser.Core.Behaviour
|
|||
private IUiElementFactory uiFactory;
|
||||
private IWorkingArea workingArea;
|
||||
|
||||
private IEnumerable<Action> ShutdownOperations
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return StopProcessMonitoring;
|
||||
yield return RestoreWorkingArea;
|
||||
yield return FinalizeApplicationLog;
|
||||
}
|
||||
}
|
||||
|
||||
public ShutdownController(
|
||||
ILogger logger,
|
||||
IMessageBox messageBox,
|
||||
|
@ -58,64 +48,62 @@ namespace SafeExamBrowser.Core.Behaviour
|
|||
this.workingArea = workingArea;
|
||||
}
|
||||
|
||||
public void FinalizeApplication()
|
||||
public void FinalizeApplication(Stack<IOperation> operations)
|
||||
{
|
||||
try
|
||||
{
|
||||
InitializeSplashScreen();
|
||||
|
||||
foreach (var operation in ShutdownOperations)
|
||||
{
|
||||
operation();
|
||||
splashScreen.UpdateProgress();
|
||||
|
||||
// TODO: Remove!
|
||||
Thread.Sleep(250);
|
||||
}
|
||||
RevertOperations(operations);
|
||||
FinalizeApplicationLog();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error($"Failed to finalize application!", e);
|
||||
messageBox.Show(text.Get(Key.MessageBox_ShutdownError), text.Get(Key.MessageBox_ShutdownErrorTitle), icon: MessageBoxIcon.Error);
|
||||
LogAndShowException(e);
|
||||
FinalizeApplicationLog(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void RevertOperations(Stack<IOperation> operations)
|
||||
{
|
||||
while (operations.Any())
|
||||
{
|
||||
var operation = operations.Pop();
|
||||
|
||||
operation.SplashScreen = splashScreen;
|
||||
operation.Revert();
|
||||
|
||||
splashScreen.Progress();
|
||||
|
||||
// TODO: Remove!
|
||||
Thread.Sleep(250);
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeSplashScreen()
|
||||
{
|
||||
splashScreen = uiFactory.CreateSplashScreen(settings, text);
|
||||
splashScreen.SetMaxProgress(ShutdownOperations.Count());
|
||||
splashScreen.SetIndeterminate();
|
||||
splashScreen.UpdateText(Key.SplashScreen_ShutdownProcedure);
|
||||
splashScreen.InvokeShow();
|
||||
logger.Info("--- Initiating shutdown procedure ---");
|
||||
}
|
||||
|
||||
private void StopProcessMonitoring()
|
||||
private void LogAndShowException(Exception e)
|
||||
{
|
||||
logger.Info("--- Stopping process monitoring ---");
|
||||
splashScreen.UpdateText(Key.SplashScreen_StopProcessMonitoring);
|
||||
|
||||
// TODO
|
||||
|
||||
processMonitor.StopMonitoringExplorer();
|
||||
logger.Error($"Failed to finalize application!", e);
|
||||
messageBox.Show(text.Get(Key.MessageBox_ShutdownError), text.Get(Key.MessageBox_ShutdownErrorTitle), icon: MessageBoxIcon.Error);
|
||||
}
|
||||
|
||||
private void RestoreWorkingArea()
|
||||
private void FinalizeApplicationLog(bool success = true)
|
||||
{
|
||||
logger.Info("--- Restoring working area ---");
|
||||
splashScreen.UpdateText(Key.SplashScreen_RestoreWorkingArea);
|
||||
|
||||
// TODO
|
||||
|
||||
workingArea.Reset();
|
||||
|
||||
splashScreen.UpdateText(Key.SplashScreen_WaitExplorerStartup, true);
|
||||
processMonitor.StartExplorerShell();
|
||||
}
|
||||
|
||||
private void FinalizeApplicationLog()
|
||||
{
|
||||
logger.Info("--- Application successfully finalized! ---");
|
||||
logger.Log($"{Environment.NewLine}# Application terminated at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
|
||||
if (success)
|
||||
{
|
||||
logger.Info("--- Application successfully finalized! ---");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Log($"{Environment.NewLine}# Application terminated at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ using SafeExamBrowser.Contracts.I18n;
|
|||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.Monitoring;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
using SafeExamBrowser.Core.Behaviour.Operations;
|
||||
|
||||
namespace SafeExamBrowser.Core.Behaviour
|
||||
{
|
||||
|
@ -34,21 +35,7 @@ namespace SafeExamBrowser.Core.Behaviour
|
|||
private IUiElementFactory uiFactory;
|
||||
private IWorkingArea workingArea;
|
||||
|
||||
private IEnumerable<Action> StartupOperations
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return HandleCommandLineArguments;
|
||||
yield return DetectOperatingSystem;
|
||||
yield return EstablishWcfServiceConnection;
|
||||
yield return DeactivateWindowsFeatures;
|
||||
yield return InitializeProcessMonitoring;
|
||||
yield return InitializeWorkingArea;
|
||||
yield return InitializeTaskbar;
|
||||
yield return InitializeBrowser;
|
||||
yield return FinishInitialization;
|
||||
}
|
||||
}
|
||||
private IEnumerable<IOperation> startupOperations;
|
||||
|
||||
public StartupController(
|
||||
IApplicationController browserController,
|
||||
|
@ -76,33 +63,78 @@ namespace SafeExamBrowser.Core.Behaviour
|
|||
this.workingArea = workingArea;
|
||||
}
|
||||
|
||||
public bool TryInitializeApplication()
|
||||
public bool TryInitializeApplication(out Stack<IOperation> operations)
|
||||
{
|
||||
operations = new Stack<IOperation>();
|
||||
|
||||
try
|
||||
{
|
||||
CreateStartupOperations();
|
||||
|
||||
InitializeApplicationLog();
|
||||
InitializeSplashScreen();
|
||||
|
||||
foreach (var operation in StartupOperations)
|
||||
{
|
||||
operation();
|
||||
splashScreen.UpdateProgress();
|
||||
operations = PerformOperations();
|
||||
|
||||
// TODO: Remove!
|
||||
Thread.Sleep(250);
|
||||
}
|
||||
FinishInitialization();
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error($"Failed to initialize application!", e);
|
||||
messageBox.Show(text.Get(Key.MessageBox_StartupError), text.Get(Key.MessageBox_StartupErrorTitle), icon: MessageBoxIcon.Error);
|
||||
LogAndShowException(e);
|
||||
RevertOperations(operations);
|
||||
FinishInitialization(false);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private Stack<IOperation> PerformOperations()
|
||||
{
|
||||
var operations = new Stack<IOperation>();
|
||||
|
||||
foreach (var operation in startupOperations)
|
||||
{
|
||||
operations.Push(operation);
|
||||
|
||||
operation.SplashScreen = splashScreen;
|
||||
operation.Perform();
|
||||
|
||||
splashScreen.Progress();
|
||||
|
||||
// TODO: Remove!
|
||||
Thread.Sleep(250);
|
||||
}
|
||||
|
||||
return operations;
|
||||
}
|
||||
|
||||
private void RevertOperations(Stack<IOperation> operations)
|
||||
{
|
||||
while (operations.Any())
|
||||
{
|
||||
var operation = operations.Pop();
|
||||
|
||||
operation.Revert();
|
||||
splashScreen.Regress();
|
||||
|
||||
// TODO: Remove!
|
||||
Thread.Sleep(250);
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateStartupOperations()
|
||||
{
|
||||
startupOperations = new IOperation[]
|
||||
{
|
||||
new ProcessMonitoringOperation(logger, processMonitor),
|
||||
new WorkingAreaOperation(logger, processMonitor, taskbar, workingArea),
|
||||
new TaskbarInitializationOperation(logger, aboutInfo, taskbar, uiFactory),
|
||||
new BrowserInitializationOperation(browserController, browserInfo, logger, taskbar, uiFactory)
|
||||
};
|
||||
}
|
||||
|
||||
private void InitializeApplicationLog()
|
||||
{
|
||||
var titleLine = $"/* {settings.ProgramTitle}, Version {settings.ProgramVersion}{Environment.NewLine}";
|
||||
|
@ -118,84 +150,29 @@ namespace SafeExamBrowser.Core.Behaviour
|
|||
private void InitializeSplashScreen()
|
||||
{
|
||||
splashScreen = uiFactory.CreateSplashScreen(settings, text);
|
||||
splashScreen.SetMaxProgress(StartupOperations.Count());
|
||||
splashScreen.SetMaxProgress(startupOperations.Count());
|
||||
splashScreen.UpdateText(Key.SplashScreen_StartupProcedure);
|
||||
splashScreen.InvokeShow();
|
||||
}
|
||||
|
||||
private void HandleCommandLineArguments()
|
||||
private void LogAndShowException(Exception e)
|
||||
{
|
||||
// TODO
|
||||
logger.Error($"Failed to initialize application!", e);
|
||||
messageBox.Show(text.Get(Key.MessageBox_StartupError), text.Get(Key.MessageBox_StartupErrorTitle), icon: MessageBoxIcon.Error);
|
||||
logger.Info("Reverting operations...");
|
||||
}
|
||||
|
||||
private void DetectOperatingSystem()
|
||||
private void FinishInitialization(bool success = true)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
private void EstablishWcfServiceConnection()
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
private void DeactivateWindowsFeatures()
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
private void InitializeProcessMonitoring()
|
||||
{
|
||||
logger.Info("--- Initializing process monitoring ---");
|
||||
splashScreen.UpdateText(Key.SplashScreen_InitializeProcessMonitoring);
|
||||
|
||||
// TODO
|
||||
|
||||
processMonitor.StartMonitoringExplorer();
|
||||
}
|
||||
|
||||
private void InitializeWorkingArea()
|
||||
{
|
||||
logger.Info("--- Initializing working area ---");
|
||||
splashScreen.UpdateText(Key.SplashScreen_WaitExplorerTermination, true);
|
||||
processMonitor.CloseExplorerShell();
|
||||
|
||||
// TODO
|
||||
// - Minimizing all open windows
|
||||
// - Emptying clipboard
|
||||
|
||||
splashScreen.UpdateText(Key.SplashScreen_InitializeWorkingArea);
|
||||
workingArea.InitializeFor(taskbar);
|
||||
}
|
||||
|
||||
private void InitializeTaskbar()
|
||||
{
|
||||
logger.Info("--- Initializing taskbar ---");
|
||||
splashScreen.UpdateText(Key.SplashScreen_InitializeTaskbar);
|
||||
|
||||
// TODO
|
||||
|
||||
var aboutNotification = uiFactory.CreateNotification(aboutInfo);
|
||||
|
||||
taskbar.AddNotification(aboutNotification);
|
||||
}
|
||||
|
||||
private void InitializeBrowser()
|
||||
{
|
||||
logger.Info("--- Initializing browser ---");
|
||||
splashScreen.UpdateText(Key.SplashScreen_InitializeBrowser);
|
||||
|
||||
// TODO
|
||||
|
||||
var browserButton = uiFactory.CreateApplicationButton(browserInfo);
|
||||
|
||||
browserController.RegisterApplicationButton(browserButton);
|
||||
taskbar.AddButton(browserButton);
|
||||
}
|
||||
|
||||
private void FinishInitialization()
|
||||
{
|
||||
logger.Info("--- Application successfully initialized! ---");
|
||||
splashScreen.InvokeClose();
|
||||
if (success)
|
||||
{
|
||||
logger.Info("--- Application successfully initialized! ---");
|
||||
splashScreen.InvokeClose();
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Log($"{Environment.NewLine}# Application terminated at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,10 @@
|
|||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Behaviour\Operations\BrowserInitializationOperation.cs" />
|
||||
<Compile Include="Behaviour\Operations\ProcessMonitoringOperation.cs" />
|
||||
<Compile Include="Behaviour\Operations\TaskbarInitializationOperation.cs" />
|
||||
<Compile Include="Behaviour\Operations\WorkingAreaOperation.cs" />
|
||||
<Compile Include="Behaviour\ShutdownController.cs" />
|
||||
<Compile Include="Behaviour\StartupController.cs" />
|
||||
<Compile Include="Logging\LogFileWriter.cs" />
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
<Image Grid.Column="0" Grid.ColumnSpan="2" Source="pack://application:,,,/SafeExamBrowser.UserInterface;component/Images/SplashScreen.png" />
|
||||
<TextBlock x:Name="InfoTextBlock" Grid.Column="1" Foreground="White" Margin="10,75,10,10" TextWrapping="Wrap" />
|
||||
</Grid>
|
||||
<ProgressBar x:Name="ProgressBar" Grid.Row="1" Minimum="0" Maximum="{Binding Path=MaxProgress}" Value="{Binding Path=CurrentProgress}" Background="#00000000" BorderThickness="0" />
|
||||
<ProgressBar x:Name="ProgressBar" Grid.Row="1" Minimum="0" Maximum="{Binding Path=MaxProgress}" Value="{Binding Path=CurrentProgress}" IsIndeterminate="{Binding Path=IsIndeterminate}" Background="#00000000" BorderThickness="0" />
|
||||
<TextBlock x:Name="StatusTextBlock" Grid.Row="1" Text="{Binding Path=Status}" FontSize="12" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" />
|
||||
</Grid>
|
||||
</Border>
|
||||
|
|
|
@ -40,16 +40,26 @@ namespace SafeExamBrowser.UserInterface
|
|||
Dispatcher.Invoke(Show);
|
||||
}
|
||||
|
||||
public void Progress(int amount = 1)
|
||||
{
|
||||
model.CurrentProgress += amount;
|
||||
}
|
||||
|
||||
public void Regress(int amount = 1)
|
||||
{
|
||||
model.CurrentProgress -= amount;
|
||||
}
|
||||
|
||||
public void SetIndeterminate()
|
||||
{
|
||||
model.IsIndeterminate = true;
|
||||
}
|
||||
|
||||
public void SetMaxProgress(int max)
|
||||
{
|
||||
model.MaxProgress = max;
|
||||
}
|
||||
|
||||
public void UpdateProgress(int amount = 1)
|
||||
{
|
||||
model.CurrentProgress += amount;
|
||||
}
|
||||
|
||||
public void UpdateText(Key key, bool showBusyIndication = false)
|
||||
{
|
||||
model.StopBusyIndication();
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Controls"
|
||||
xmlns:s="clr-namespace:System;assembly=mscorlib"
|
||||
mc:Ignorable="d"
|
||||
Title="Taskbar" Height="40" Width="750" WindowStyle="None" AllowsTransparency="True" Topmost="True" Icon="./Images/SafeExamBrowser.ico">
|
||||
Title="Taskbar" Height="40" Width="750" WindowStyle="None" AllowsTransparency="True" Topmost="True" Visibility="Collapsed" Icon="./Images/SafeExamBrowser.ico">
|
||||
<Window.Background>
|
||||
<SolidColorBrush Color="Black" Opacity="0.8" />
|
||||
</Window.Background>
|
||||
|
|
|
@ -14,6 +14,7 @@ namespace SafeExamBrowser.UserInterface.ViewModels
|
|||
class SplashScreenViewModel : INotifyPropertyChanged
|
||||
{
|
||||
private int currentProgress;
|
||||
private bool isIndeterminate;
|
||||
private int maxProgress;
|
||||
private string status;
|
||||
private Timer busyTimer;
|
||||
|
@ -33,6 +34,19 @@ namespace SafeExamBrowser.UserInterface.ViewModels
|
|||
}
|
||||
}
|
||||
|
||||
public bool IsIndeterminate
|
||||
{
|
||||
get
|
||||
{
|
||||
return isIndeterminate;
|
||||
}
|
||||
set
|
||||
{
|
||||
isIndeterminate = value;
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsIndeterminate)));
|
||||
}
|
||||
}
|
||||
|
||||
public int MaxProgress
|
||||
{
|
||||
get
|
||||
|
|
|
@ -7,8 +7,10 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using SafeExamBrowser.Contracts.Behaviour;
|
||||
|
||||
namespace SafeExamBrowser
|
||||
{
|
||||
|
@ -57,12 +59,12 @@ namespace SafeExamBrowser
|
|||
|
||||
instances.BuildObjectGraph();
|
||||
|
||||
var success = instances.StartupController.TryInitializeApplication();
|
||||
var success = instances.StartupController.TryInitializeApplication(out Stack<IOperation> operations);
|
||||
|
||||
if (success)
|
||||
{
|
||||
MainWindow = instances.Taskbar;
|
||||
MainWindow.Closing += (o, args) => ShutdownApplication();
|
||||
MainWindow.Closing += (o, args) => ShutdownApplication(operations);
|
||||
MainWindow.Show();
|
||||
}
|
||||
else
|
||||
|
@ -71,10 +73,10 @@ namespace SafeExamBrowser
|
|||
}
|
||||
}
|
||||
|
||||
private void ShutdownApplication()
|
||||
private void ShutdownApplication(Stack<IOperation> operations)
|
||||
{
|
||||
MainWindow.Hide();
|
||||
instances.ShutdownController.FinalizeApplication();
|
||||
instances.ShutdownController.FinalizeApplication(operations);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue