From 31857bfb25dafbb0fd2b003182cf12f2e0414255 Mon Sep 17 00:00:00 2001 From: dbuechel Date: Fri, 8 Mar 2019 15:56:38 +0100 Subject: [PATCH] SEBWIN-141: Extended system component contracts and implementations to allow multiple controls per component and started to implement action center functionality. --- .../Operations/BrowserOperationTests.cs | 10 +- ...erationTests.cs => ShellOperationTests.cs} | 38 ++- .../SafeExamBrowser.Client.UnitTests.csproj | 2 +- SafeExamBrowser.Client/CompositionRoot.cs | 44 +-- .../Operations/ActionCenterOperation.cs | 114 -------- .../Operations/ShellOperation.cs | 275 ++++++++++++++++++ .../Operations/TaskbarOperation.cs | 183 ------------ .../SafeExamBrowser.Client.csproj | 3 +- .../ConfigurationData/DataValues.cs | 1 + .../Settings/ActionCenterSettings.cs | 5 + SafeExamBrowser.Contracts/I18n/TextKey.cs | 6 +- .../SystemComponents/ISystemComponent.cs | 9 +- .../UserInterface/IUserInterfaceFactory.cs | 4 +- .../UserInterface/Shell/ISystemControl.cs | 4 +- SafeExamBrowser.I18n/Text.xml | 14 +- .../KeyboardLayout.cs | 34 ++- .../PowerSupply.cs | 80 ++--- .../WirelessNetwork.cs | 111 ++++--- .../ActionCenter.xaml | 10 +- .../ActionCenter.xaml.cs | 10 +- .../ActionCenterNotificationButton.xaml | 28 ++ .../ActionCenterNotificationButton.xaml.cs | 40 +++ ...on.xaml => TaskbarNotificationButton.xaml} | 2 +- ...l.cs => TaskbarNotificationButton.xaml.cs} | 4 +- ...feExamBrowser.UserInterface.Desktop.csproj | 13 +- .../UserInterfaceFactory.cs | 11 +- 26 files changed, 579 insertions(+), 476 deletions(-) rename SafeExamBrowser.Client.UnitTests/Operations/{TaskbarOperationTests.cs => ShellOperationTests.cs} (74%) delete mode 100644 SafeExamBrowser.Client/Operations/ActionCenterOperation.cs create mode 100644 SafeExamBrowser.Client/Operations/ShellOperation.cs delete mode 100644 SafeExamBrowser.Client/Operations/TaskbarOperation.cs create mode 100644 SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterNotificationButton.xaml create mode 100644 SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterNotificationButton.xaml.cs rename SafeExamBrowser.UserInterface.Desktop/Controls/{NotificationButton.xaml => TaskbarNotificationButton.xaml} (96%) rename SafeExamBrowser.UserInterface.Desktop/Controls/{NotificationButton.xaml.cs => TaskbarNotificationButton.xaml.cs} (87%) diff --git a/SafeExamBrowser.Client.UnitTests/Operations/BrowserOperationTests.cs b/SafeExamBrowser.Client.UnitTests/Operations/BrowserOperationTests.cs index 70a2eb7e..a575b642 100644 --- a/SafeExamBrowser.Client.UnitTests/Operations/BrowserOperationTests.cs +++ b/SafeExamBrowser.Client.UnitTests/Operations/BrowserOperationTests.cs @@ -44,16 +44,11 @@ namespace SafeExamBrowser.Client.UnitTests.Operations [TestMethod] public void MustPeformCorrectly() { - var order = 0; - - controller.Setup(c => c.Initialize()).Callback(() => Assert.AreEqual(++order, 1)); - controller.Setup(c => c.RegisterApplicationControl(It.IsAny())).Callback(() => Assert.AreEqual(++order, 2)); - taskbar.Setup(t => t.AddApplicationControl(It.IsAny())).Callback(() => Assert.AreEqual(++order, 3)); - sut.Perform(); controller.Verify(c => c.Initialize(), Times.Once); - controller.Verify(c => c.RegisterApplicationControl(It.IsAny()), Times.Once); + controller.Verify(c => c.RegisterApplicationControl(It.IsAny()), Times.Exactly(2)); + actionCenter.Verify(a => a.AddApplicationControl(It.IsAny()), Times.Once); taskbar.Verify(t => t.AddApplicationControl(It.IsAny()), Times.Once); } @@ -61,7 +56,6 @@ namespace SafeExamBrowser.Client.UnitTests.Operations public void MustRevertCorrectly() { sut.Revert(); - controller.Verify(c => c.Terminate(), Times.Once); } } diff --git a/SafeExamBrowser.Client.UnitTests/Operations/TaskbarOperationTests.cs b/SafeExamBrowser.Client.UnitTests/Operations/ShellOperationTests.cs similarity index 74% rename from SafeExamBrowser.Client.UnitTests/Operations/TaskbarOperationTests.cs rename to SafeExamBrowser.Client.UnitTests/Operations/ShellOperationTests.cs index 41d10e5d..9c326314 100644 --- a/SafeExamBrowser.Client.UnitTests/Operations/TaskbarOperationTests.cs +++ b/SafeExamBrowser.Client.UnitTests/Operations/ShellOperationTests.cs @@ -6,6 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +using System.Collections.Generic; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using SafeExamBrowser.Client.Operations; @@ -19,10 +20,13 @@ using SafeExamBrowser.Contracts.UserInterface.Shell; namespace SafeExamBrowser.Client.UnitTests.Operations { [TestClass] - public class TaskbarOperationTests + public class ShellOperationTests { + private Mock actionCenter; + private Mock> activators; + private ActionCenterSettings actionCenterSettings; private Mock loggerMock; - private TaskbarSettings settings; + private TaskbarSettings taskbarSettings; private Mock aboutInfoMock; private Mock aboutControllerMock; private Mock logInfoMock; @@ -34,11 +38,14 @@ namespace SafeExamBrowser.Client.UnitTests.Operations private Mock taskbarMock; private Mock uiFactoryMock; - private TaskbarOperation sut; + private ShellOperation sut; [TestInitialize] public void Initialize() { + actionCenter = new Mock(); + activators = new Mock>(); + actionCenterSettings = new ActionCenterSettings(); loggerMock = new Mock(); aboutInfoMock = new Mock(); aboutControllerMock = new Mock(); @@ -49,17 +56,20 @@ namespace SafeExamBrowser.Client.UnitTests.Operations wirelessNetworkMock = new Mock>(); systemInfoMock = new Mock(); taskbarMock = new Mock(); - settings = new TaskbarSettings(); + taskbarSettings = new TaskbarSettings(); uiFactoryMock = new Mock(); - settings.AllowApplicationLog = true; - settings.AllowKeyboardLayout = true; - settings.AllowWirelessNetwork = true; - settings.EnableTaskbar = true; + taskbarSettings.AllowApplicationLog = true; + taskbarSettings.AllowKeyboardLayout = true; + taskbarSettings.AllowWirelessNetwork = true; + taskbarSettings.EnableTaskbar = true; systemInfoMock.SetupGet(s => s.HasBattery).Returns(true); - uiFactoryMock.Setup(u => u.CreateNotificationControl(It.IsAny())).Returns(new Mock().Object); + uiFactoryMock.Setup(u => u.CreateNotificationControl(It.IsAny(), It.IsAny())).Returns(new Mock().Object); - sut = new TaskbarOperation( + sut = new ShellOperation( + actionCenter.Object, + activators.Object, + actionCenterSettings, loggerMock.Object, aboutInfoMock.Object, aboutControllerMock.Object, @@ -70,7 +80,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations wirelessNetworkMock.Object, systemInfoMock.Object, taskbarMock.Object, - settings, + taskbarSettings, uiFactoryMock.Object); } @@ -79,9 +89,9 @@ namespace SafeExamBrowser.Client.UnitTests.Operations { sut.Perform(); - keyboardLayoutMock.Verify(k => k.Initialize(It.IsAny()), Times.Once); - powerSupplyMock.Verify(p => p.Initialize(It.IsAny()), Times.Once); - wirelessNetworkMock.Verify(w => w.Initialize(It.IsAny()), Times.Once); + keyboardLayoutMock.Verify(k => k.Initialize(), Times.Once); + powerSupplyMock.Verify(p => p.Initialize(), Times.Once); + wirelessNetworkMock.Verify(w => w.Initialize(), Times.Once); taskbarMock.Verify(t => t.AddSystemControl(It.IsAny()), Times.Exactly(3)); taskbarMock.Verify(t => t.AddNotificationControl(It.IsAny()), Times.Exactly(2)); } diff --git a/SafeExamBrowser.Client.UnitTests/SafeExamBrowser.Client.UnitTests.csproj b/SafeExamBrowser.Client.UnitTests/SafeExamBrowser.Client.UnitTests.csproj index 24cb590b..228e2360 100644 --- a/SafeExamBrowser.Client.UnitTests/SafeExamBrowser.Client.UnitTests.csproj +++ b/SafeExamBrowser.Client.UnitTests/SafeExamBrowser.Client.UnitTests.csproj @@ -90,7 +90,7 @@ - + diff --git a/SafeExamBrowser.Client/CompositionRoot.cs b/SafeExamBrowser.Client/CompositionRoot.cs index 25af166c..54b934dd 100644 --- a/SafeExamBrowser.Client/CompositionRoot.cs +++ b/SafeExamBrowser.Client/CompositionRoot.cs @@ -116,8 +116,7 @@ namespace SafeExamBrowser.Client operations.Enqueue(new LazyInitializationOperation(BuildWindowMonitorOperation)); operations.Enqueue(new LazyInitializationOperation(BuildProcessMonitorOperation)); operations.Enqueue(new DisplayMonitorOperation(displayMonitor, logger, taskbar)); - operations.Enqueue(new LazyInitializationOperation(BuildActionCenterOperation)); - operations.Enqueue(new LazyInitializationOperation(BuildTaskbarOperation)); + operations.Enqueue(new LazyInitializationOperation(BuildShellOperation)); operations.Enqueue(new LazyInitializationOperation(BuildBrowserOperation)); operations.Enqueue(new ClipboardOperation(logger, nativeMethods)); operations.Enqueue(new DelegateOperation(UpdateClientControllerDependencies)); @@ -196,35 +195,6 @@ namespace SafeExamBrowser.Client textResource = new XmlTextResource(path); } - private IOperation BuildActionCenterOperation() - { - var aboutInfo = new AboutNotificationInfo(text); - var aboutController = new AboutNotificationController(configuration.AppConfig, uiFactory); - var logInfo = new LogNotificationInfo(text); - var logController = new LogNotificationController(logger, uiFactory); - var activators = new IActionCenterActivator[] - { - new KeyboardActivator(new ModuleLogger(logger, nameof(KeyboardActivator))), - new TouchActivator(new ModuleLogger(logger, nameof(TouchActivator))) - }; - var operation = new ActionCenterOperation( - actionCenter, - activators, - logger, - aboutInfo, - aboutController, - logInfo, - logController, - keyboardLayout, - powerSupply, - wirelessNetwork, - configuration.Settings.ActionCenter, - systemInfo, - uiFactory); - - return operation; - } - private IOperation BuildBrowserOperation() { var moduleLogger = new ModuleLogger(logger, "BrowserController"); @@ -280,13 +250,21 @@ namespace SafeExamBrowser.Client return new ProcessMonitorOperation(logger, processMonitor, configuration.Settings); } - private IOperation BuildTaskbarOperation() + private IOperation BuildShellOperation() { var aboutInfo = new AboutNotificationInfo(text); var aboutController = new AboutNotificationController(configuration.AppConfig, uiFactory); var logInfo = new LogNotificationInfo(text); var logController = new LogNotificationController(logger, uiFactory); - var operation = new TaskbarOperation( + var activators = new IActionCenterActivator[] + { + new KeyboardActivator(new ModuleLogger(logger, nameof(KeyboardActivator))), + new TouchActivator(new ModuleLogger(logger, nameof(TouchActivator))) + }; + var operation = new ShellOperation( + actionCenter, + activators, + configuration.Settings.ActionCenter, logger, aboutInfo, aboutController, diff --git a/SafeExamBrowser.Client/Operations/ActionCenterOperation.cs b/SafeExamBrowser.Client/Operations/ActionCenterOperation.cs deleted file mode 100644 index b40ad0b8..00000000 --- a/SafeExamBrowser.Client/Operations/ActionCenterOperation.cs +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2019 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.Collections.Generic; -using SafeExamBrowser.Contracts.Client; -using SafeExamBrowser.Contracts.Configuration.Settings; -using SafeExamBrowser.Contracts.Core.OperationModel; -using SafeExamBrowser.Contracts.Core.OperationModel.Events; -using SafeExamBrowser.Contracts.I18n; -using SafeExamBrowser.Contracts.Logging; -using SafeExamBrowser.Contracts.SystemComponents; -using SafeExamBrowser.Contracts.UserInterface; -using SafeExamBrowser.Contracts.UserInterface.Shell; - -namespace SafeExamBrowser.Client.Operations -{ - internal class ActionCenterOperation : IOperation - { - private IActionCenter actionCenter; - private IEnumerable activators; - private ILogger logger; - private INotificationInfo aboutInfo; - private INotificationController aboutController; - private INotificationInfo logInfo; - private INotificationController logController; - private ISystemComponent keyboardLayout; - private ISystemComponent powerSupply; - private ISystemComponent wirelessNetwork; - private ActionCenterSettings settings; - private ISystemInfo systemInfo; - private IUserInterfaceFactory uiFactory; - - public event ActionRequiredEventHandler ActionRequired { add { } remove { } } - public event StatusChangedEventHandler StatusChanged; - - public ActionCenterOperation( - IActionCenter actionCenter, - IEnumerable activators, - ILogger logger, - INotificationInfo aboutInfo, - INotificationController aboutController, - INotificationInfo logInfo, - INotificationController logController, - ISystemComponent keyboardLayout, - ISystemComponent powerSupply, - ISystemComponent wirelessNetwork, - ActionCenterSettings settings, - ISystemInfo systemInfo, - IUserInterfaceFactory uiFactory) - { - this.actionCenter = actionCenter; - this.activators = activators; - this.logger = logger; - this.aboutInfo = aboutInfo; - this.aboutController = aboutController; - this.logInfo = logInfo; - this.logController = logController; - this.keyboardLayout = keyboardLayout; - this.powerSupply = powerSupply; - this.wirelessNetwork = wirelessNetwork; - this.systemInfo = systemInfo; - this.settings = settings; - this.uiFactory = uiFactory; - } - - public OperationResult Perform() - { - StatusChanged?.Invoke(TextKey.OperationStatus_InitializeActionCenter); - - if (settings.EnableActionCenter) - { - logger.Info("Initializing action center..."); - - foreach (var activator in activators) - { - actionCenter.Register(activator); - activator.Start(); - } - } - else - { - logger.Info("Action center is disabled, skipping initialization."); - } - - return OperationResult.Success; - } - - public OperationResult Revert() - { - StatusChanged?.Invoke(TextKey.OperationStatus_TerminateActionCenter); - - if (settings.EnableActionCenter) - { - logger.Info("Terminating action center..."); - - foreach (var activator in activators) - { - activator.Stop(); - } - } - else - { - logger.Info("Action center was disabled, skipping termination."); - } - - return OperationResult.Success; - } - } -} diff --git a/SafeExamBrowser.Client/Operations/ShellOperation.cs b/SafeExamBrowser.Client/Operations/ShellOperation.cs new file mode 100644 index 00000000..3422b7c8 --- /dev/null +++ b/SafeExamBrowser.Client/Operations/ShellOperation.cs @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2019 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.Collections.Generic; +using SafeExamBrowser.Contracts.Client; +using SafeExamBrowser.Contracts.Configuration.Settings; +using SafeExamBrowser.Contracts.Core.OperationModel; +using SafeExamBrowser.Contracts.Core.OperationModel.Events; +using SafeExamBrowser.Contracts.I18n; +using SafeExamBrowser.Contracts.Logging; +using SafeExamBrowser.Contracts.SystemComponents; +using SafeExamBrowser.Contracts.UserInterface; +using SafeExamBrowser.Contracts.UserInterface.Shell; + +namespace SafeExamBrowser.Client.Operations +{ + internal class ShellOperation : IOperation + { + private IActionCenter actionCenter; + private IEnumerable activators; + private ActionCenterSettings actionCenterSettings; + private ILogger logger; + private INotificationInfo aboutInfo; + private INotificationController aboutController; + private INotificationInfo logInfo; + private INotificationController logController; + private ISystemComponent keyboardLayout; + private ISystemComponent powerSupply; + private ISystemComponent wirelessNetwork; + private ISystemInfo systemInfo; + private ITaskbar taskbar; + private TaskbarSettings taskbarSettings; + private IUserInterfaceFactory uiFactory; + + public event ActionRequiredEventHandler ActionRequired { add { } remove { } } + public event StatusChangedEventHandler StatusChanged; + + public ShellOperation( + IActionCenter actionCenter, + IEnumerable activators, + ActionCenterSettings actionCenterSettings, + ILogger logger, + INotificationInfo aboutInfo, + INotificationController aboutController, + INotificationInfo logInfo, + INotificationController logController, + ISystemComponent keyboardLayout, + ISystemComponent powerSupply, + ISystemComponent wirelessNetwork, + ISystemInfo systemInfo, + ITaskbar taskbar, + TaskbarSettings taskbarSettings, + IUserInterfaceFactory uiFactory) + { + this.aboutInfo = aboutInfo; + this.aboutController = aboutController; + this.actionCenter = actionCenter; + this.activators = activators; + this.actionCenterSettings = actionCenterSettings; + this.logger = logger; + this.logInfo = logInfo; + this.logController = logController; + this.keyboardLayout = keyboardLayout; + this.powerSupply = powerSupply; + this.taskbarSettings = taskbarSettings; + this.systemInfo = systemInfo; + this.taskbar = taskbar; + this.uiFactory = uiFactory; + this.wirelessNetwork = wirelessNetwork; + } + + public OperationResult Perform() + { + logger.Info("Initializing shell..."); + StatusChanged?.Invoke(TextKey.OperationStatus_InitializeShell); + + InitializeSystemComponents(); + InitializeActionCenter(); + InitializeTaskbar(); + + return OperationResult.Success; + } + + public OperationResult Revert() + { + logger.Info("Terminating shell..."); + StatusChanged?.Invoke(TextKey.OperationStatus_TerminateShell); + + TerminateNotifications(); + TerminateSystemComponents(); + + return OperationResult.Success; + } + + private void InitializeActionCenter() + { + if (actionCenterSettings.EnableActionCenter) + { + logger.Info("Initializing action center..."); + + InitializeAboutNotificationForActionCenter(); + InitializeClockForActionCenter(); + InitializeLogNotificationForActionCenter(); + InitializeKeyboardLayoutForActionCenter(); + InitializeWirelessNetworkForActionCenter(); + InitializePowerSupplyForActionCenter(); + + //if (settings.AllowKeyboardLayout) + //{ + // AddKeyboardLayoutControl(); + //} + + //if (settings.AllowWirelessNetwork) + //{ + // AddWirelessNetworkControl(); + //} + + //if (systemInfo.HasBattery) + //{ + // AddPowerSupplyControl(); + //} + + foreach (var activator in activators) + { + actionCenter.Register(activator); + activator.Start(); + } + } + else + { + logger.Info("Action center is disabled, skipping initialization."); + } + } + + private void InitializeTaskbar() + { + if (taskbarSettings.EnableTaskbar) + { + logger.Info("Initializing taskbar..."); + + InitializeAboutNotificationForTaskbar(); + InitializeClockForTaskbar(); + InitializeLogNotificationForTaskbar(); + InitializeKeyboardLayoutForTaskbar(); + InitializeWirelessNetworkForTaskbar(); + InitializePowerSupplyForTaskbar(); + } + else + { + logger.Info("Taskbar is disabled, skipping initialization."); + } + } + + private void InitializeSystemComponents() + { + keyboardLayout.Initialize(); + powerSupply.Initialize(); + wirelessNetwork.Initialize(); + } + + private void InitializeAboutNotificationForActionCenter() + { + var notification = uiFactory.CreateNotificationControl(aboutInfo, Location.ActionCenter); + + aboutController.RegisterNotification(notification); + actionCenter.AddNotificationControl(notification); + } + + private void InitializeAboutNotificationForTaskbar() + { + var notification = uiFactory.CreateNotificationControl(aboutInfo, Location.Taskbar); + + aboutController.RegisterNotification(notification); + taskbar.AddNotificationControl(notification); + } + + private void InitializeClockForActionCenter() + { + //TODO: actionCenter.ShowClock = settings.ShowClock; + } + + private void InitializeClockForTaskbar() + { + taskbar.ShowClock = taskbarSettings.ShowClock; + } + + private void InitializeLogNotificationForActionCenter() + { + if (actionCenterSettings.AllowApplicationLog) + { + var notification = uiFactory.CreateNotificationControl(logInfo, Location.ActionCenter); + + logController.RegisterNotification(notification); + actionCenter.AddNotificationControl(notification); + } + } + + private void InitializeLogNotificationForTaskbar() + { + if (taskbarSettings.AllowApplicationLog) + { + var notification = uiFactory.CreateNotificationControl(logInfo, Location.Taskbar); + + logController.RegisterNotification(notification); + taskbar.AddNotificationControl(notification); + } + } + + private void InitializeKeyboardLayoutForActionCenter() + { + // TODO + } + + private void InitializeKeyboardLayoutForTaskbar() + { + if (taskbarSettings.AllowKeyboardLayout) + { + var control = uiFactory.CreateKeyboardLayoutControl(); + + keyboardLayout.Register(control); + taskbar.AddSystemControl(control); + } + } + + private void InitializePowerSupplyForActionCenter() + { + // TODO + } + + private void InitializePowerSupplyForTaskbar() + { + if (systemInfo.HasBattery) + { + var control = uiFactory.CreatePowerSupplyControl(); + + powerSupply.Register(control); + taskbar.AddSystemControl(control); + } + } + + private void InitializeWirelessNetworkForActionCenter() + { + // TODO + } + + private void InitializeWirelessNetworkForTaskbar() + { + if (taskbarSettings.AllowWirelessNetwork) + { + var control = uiFactory.CreateWirelessNetworkControl(); + + wirelessNetwork.Register(control); + taskbar.AddSystemControl(control); + } + } + + private void TerminateNotifications() + { + aboutController.Terminate(); + logController.Terminate(); + } + + private void TerminateSystemComponents() + { + keyboardLayout.Terminate(); + powerSupply.Terminate(); + wirelessNetwork.Terminate(); + } + } +} diff --git a/SafeExamBrowser.Client/Operations/TaskbarOperation.cs b/SafeExamBrowser.Client/Operations/TaskbarOperation.cs deleted file mode 100644 index 2c2ec455..00000000 --- a/SafeExamBrowser.Client/Operations/TaskbarOperation.cs +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (c) 2019 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.Client; -using SafeExamBrowser.Contracts.Configuration.Settings; -using SafeExamBrowser.Contracts.Core.OperationModel; -using SafeExamBrowser.Contracts.Core.OperationModel.Events; -using SafeExamBrowser.Contracts.I18n; -using SafeExamBrowser.Contracts.Logging; -using SafeExamBrowser.Contracts.SystemComponents; -using SafeExamBrowser.Contracts.UserInterface; -using SafeExamBrowser.Contracts.UserInterface.Shell; - -namespace SafeExamBrowser.Client.Operations -{ - internal class TaskbarOperation : IOperation - { - private ILogger logger; - private INotificationInfo aboutInfo; - private INotificationController aboutController; - private INotificationInfo logInfo; - private INotificationController logController; - private TaskbarSettings settings; - private ISystemComponent keyboardLayout; - private ISystemComponent powerSupply; - private ISystemComponent wirelessNetwork; - private ISystemInfo systemInfo; - private ITaskbar taskbar; - private IUserInterfaceFactory uiFactory; - - public event ActionRequiredEventHandler ActionRequired { add { } remove { } } - public event StatusChangedEventHandler StatusChanged; - - public TaskbarOperation( - ILogger logger, - INotificationInfo aboutInfo, - INotificationController aboutController, - INotificationInfo logInfo, - INotificationController logController, - ISystemComponent keyboardLayout, - ISystemComponent powerSupply, - ISystemComponent wirelessNetwork, - ISystemInfo systemInfo, - ITaskbar taskbar, - TaskbarSettings settings, - IUserInterfaceFactory uiFactory) - { - this.aboutInfo = aboutInfo; - this.aboutController = aboutController; - this.logger = logger; - this.logInfo = logInfo; - this.logController = logController; - this.keyboardLayout = keyboardLayout; - this.powerSupply = powerSupply; - this.settings = settings; - this.systemInfo = systemInfo; - this.taskbar = taskbar; - this.uiFactory = uiFactory; - this.wirelessNetwork = wirelessNetwork; - } - - public OperationResult Perform() - { - StatusChanged?.Invoke(TextKey.OperationStatus_InitializeTaskbar); - - if (settings.EnableTaskbar) - { - logger.Info("Initializing taskbar..."); - - AddAboutNotification(); - taskbar.ShowClock = settings.ShowClock; - - if (settings.AllowApplicationLog) - { - AddLogNotification(); - } - - if (settings.AllowKeyboardLayout) - { - AddKeyboardLayoutControl(); - } - - if (settings.AllowWirelessNetwork) - { - AddWirelessNetworkControl(); - } - - if (systemInfo.HasBattery) - { - AddPowerSupplyControl(); - } - } - else - { - logger.Info("Taskbar is disabled, skipping initialization."); - } - - return OperationResult.Success; - } - - public OperationResult Revert() - { - StatusChanged?.Invoke(TextKey.OperationStatus_TerminateTaskbar); - - if (settings.EnableTaskbar) - { - logger.Info("Terminating taskbar..."); - aboutController.Terminate(); - - if (settings.AllowApplicationLog) - { - logController.Terminate(); - } - - if (settings.AllowKeyboardLayout) - { - keyboardLayout.Terminate(); - } - - if (settings.AllowWirelessNetwork) - { - wirelessNetwork.Terminate(); - } - - if (systemInfo.HasBattery) - { - powerSupply.Terminate(); - } - } - else - { - logger.Info("Taskbar was disabled, skipping termination."); - } - - return OperationResult.Success; - } - - private void AddAboutNotification() - { - var aboutNotification = uiFactory.CreateNotificationControl(aboutInfo); - - aboutController.RegisterNotification(aboutNotification); - taskbar.AddNotificationControl(aboutNotification); - } - - private void AddKeyboardLayoutControl() - { - var control = uiFactory.CreateKeyboardLayoutControl(); - - keyboardLayout.Initialize(control); - taskbar.AddSystemControl(control); - } - - private void AddLogNotification() - { - var logNotification = uiFactory.CreateNotificationControl(logInfo); - - logController.RegisterNotification(logNotification); - taskbar.AddNotificationControl(logNotification); - } - - private void AddPowerSupplyControl() - { - var control = uiFactory.CreatePowerSupplyControl(); - - powerSupply.Initialize(control); - taskbar.AddSystemControl(control); - } - - private void AddWirelessNetworkControl() - { - var control = uiFactory.CreateWirelessNetworkControl(); - - wirelessNetwork.Initialize(control); - taskbar.AddSystemControl(control); - } - } -} diff --git a/SafeExamBrowser.Client/SafeExamBrowser.Client.csproj b/SafeExamBrowser.Client/SafeExamBrowser.Client.csproj index 12e31887..85232c1e 100644 --- a/SafeExamBrowser.Client/SafeExamBrowser.Client.csproj +++ b/SafeExamBrowser.Client/SafeExamBrowser.Client.csproj @@ -72,7 +72,6 @@ - @@ -91,7 +90,7 @@ - + Code diff --git a/SafeExamBrowser.Configuration/ConfigurationData/DataValues.cs b/SafeExamBrowser.Configuration/ConfigurationData/DataValues.cs index 7b9963f7..c9dac541 100644 --- a/SafeExamBrowser.Configuration/ConfigurationData/DataValues.cs +++ b/SafeExamBrowser.Configuration/ConfigurationData/DataValues.cs @@ -145,6 +145,7 @@ namespace SafeExamBrowser.Configuration.ConfigurationData settings.Taskbar.ShowClock = true; // TODO: Default values for testing of alpha version only, remove for final release! + settings.ActionCenter.AllowApplicationLog = true; settings.Browser.AllowDeveloperConsole = true; settings.Browser.MainWindowSettings.AllowAddressBar = true; settings.Taskbar.AllowApplicationLog = true; diff --git a/SafeExamBrowser.Contracts/Configuration/Settings/ActionCenterSettings.cs b/SafeExamBrowser.Contracts/Configuration/Settings/ActionCenterSettings.cs index b4c8a819..534d87be 100644 --- a/SafeExamBrowser.Contracts/Configuration/Settings/ActionCenterSettings.cs +++ b/SafeExamBrowser.Contracts/Configuration/Settings/ActionCenterSettings.cs @@ -16,6 +16,11 @@ namespace SafeExamBrowser.Contracts.Configuration.Settings [Serializable] public class ActionCenterSettings { + /// + /// Determines whether the user may access the application log during runtime. + /// + public bool AllowApplicationLog { get; set; } + /// /// Determines whether the action center itself is enabled and visible to the user. /// diff --git a/SafeExamBrowser.Contracts/I18n/TextKey.cs b/SafeExamBrowser.Contracts/I18n/TextKey.cs index 8ede288c..4fe9efa2 100644 --- a/SafeExamBrowser.Contracts/I18n/TextKey.cs +++ b/SafeExamBrowser.Contracts/I18n/TextKey.cs @@ -56,7 +56,6 @@ namespace SafeExamBrowser.Contracts.I18n OperationStatus_CloseRuntimeConnection, OperationStatus_EmptyClipboard, OperationStatus_FinalizeServiceSession, - OperationStatus_InitializeActionCenter, OperationStatus_InitializeBrowser, OperationStatus_InitializeClient, OperationStatus_InitializeConfiguration, @@ -64,7 +63,7 @@ namespace SafeExamBrowser.Contracts.I18n OperationStatus_InitializeProcessMonitoring, OperationStatus_InitializeRuntimeConnection, OperationStatus_InitializeServiceSession, - OperationStatus_InitializeTaskbar, + OperationStatus_InitializeShell, OperationStatus_InitializeWindowMonitoring, OperationStatus_InitializeWorkingArea, OperationStatus_RestartCommunicationHost, @@ -81,9 +80,8 @@ namespace SafeExamBrowser.Contracts.I18n OperationStatus_StopMouseInterception, OperationStatus_StopProcessMonitoring, OperationStatus_StopWindowMonitoring, - OperationStatus_TerminateActionCenter, OperationStatus_TerminateBrowser, - OperationStatus_TerminateTaskbar, + OperationStatus_TerminateShell, OperationStatus_WaitExplorerStartup, OperationStatus_WaitExplorerTermination, OperationStatus_WaitRuntimeDisconnection, diff --git a/SafeExamBrowser.Contracts/SystemComponents/ISystemComponent.cs b/SafeExamBrowser.Contracts/SystemComponents/ISystemComponent.cs index 4ef9f60d..1b721735 100644 --- a/SafeExamBrowser.Contracts/SystemComponents/ISystemComponent.cs +++ b/SafeExamBrowser.Contracts/SystemComponents/ISystemComponent.cs @@ -17,9 +17,14 @@ namespace SafeExamBrowser.Contracts.SystemComponents public interface ISystemComponent where TControl : ISystemControl { /// - /// Initializes the resources and operations of the component and registers its taskbar control. + /// Initializes the resources and operations of the component. /// - void Initialize(TControl control); + void Initialize(); + + /// + /// Registers a system control which will be loaded into shell. + /// + void Register(TControl control); /// /// Instructs the component to stop any running operations and releases all used resources. diff --git a/SafeExamBrowser.Contracts/UserInterface/IUserInterfaceFactory.cs b/SafeExamBrowser.Contracts/UserInterface/IUserInterfaceFactory.cs index d12a2744..064b16e4 100644 --- a/SafeExamBrowser.Contracts/UserInterface/IUserInterfaceFactory.cs +++ b/SafeExamBrowser.Contracts/UserInterface/IUserInterfaceFactory.cs @@ -51,9 +51,9 @@ namespace SafeExamBrowser.Contracts.UserInterface IWindow CreateLogWindow(ILogger logger); /// - /// Creates a notification control, initialized with the given notification information. + /// Creates a notification control for the specified location, initialized with the given notification information. /// - INotificationControl CreateNotificationControl(INotificationInfo info); + INotificationControl CreateNotificationControl(INotificationInfo info, Location location); /// /// Creates a password dialog with the given message and title. diff --git a/SafeExamBrowser.Contracts/UserInterface/Shell/ISystemControl.cs b/SafeExamBrowser.Contracts/UserInterface/Shell/ISystemControl.cs index 6e3f7062..b47f5f1a 100644 --- a/SafeExamBrowser.Contracts/UserInterface/Shell/ISystemControl.cs +++ b/SafeExamBrowser.Contracts/UserInterface/Shell/ISystemControl.cs @@ -9,12 +9,12 @@ namespace SafeExamBrowser.Contracts.UserInterface.Shell { /// - /// The control of a system component which can be loaded into the . + /// The control of a system component which can be loaded into the shell. /// public interface ISystemControl { /// - /// Closes any pop-up windows associated with this control. + /// Closes the control and / or any associated user interface elements. /// void Close(); diff --git a/SafeExamBrowser.I18n/Text.xml b/SafeExamBrowser.I18n/Text.xml index 861b0555..254a8b10 100644 --- a/SafeExamBrowser.I18n/Text.xml +++ b/SafeExamBrowser.I18n/Text.xml @@ -126,9 +126,6 @@ Finalizing service session - - Initializing action center - Initializing browser @@ -153,8 +150,8 @@ Initializing new session - - Initializing taskbar + + Initializing user interface Initializing window monitoring @@ -201,14 +198,11 @@ Stopping window monitoring - - Terminating action center - Terminating browser - - Terminating taskbar + + Terminating user interface Waiting for Windows explorer to start up diff --git a/SafeExamBrowser.SystemComponents/KeyboardLayout.cs b/SafeExamBrowser.SystemComponents/KeyboardLayout.cs index c3e6c93c..b9322d5b 100644 --- a/SafeExamBrowser.SystemComponents/KeyboardLayout.cs +++ b/SafeExamBrowser.SystemComponents/KeyboardLayout.cs @@ -21,23 +21,19 @@ namespace SafeExamBrowser.SystemComponents private IList layouts = new List(); private ILogger logger; private InputLanguage originalLanguage; - private ISystemKeyboardLayoutControl control; + private IList controls; private IText text; public KeyboardLayout(ILogger logger, IText text) { + this.controls = new List(); this.logger = logger; this.text = text; } - public void Initialize(ISystemKeyboardLayoutControl control) + public void Initialize() { - this.control = control; - originalLanguage = InputLanguage.CurrentInputLanguage; - control.LayoutSelected += Control_LayoutSelected; - control.SetTooltip(text.Get(TextKey.SystemControl_KeyboardLayoutTooltip)); - logger.Info($"Saved current keyboard layout {ToString(originalLanguage)}."); foreach (InputLanguage language in InputLanguage.InstalledInputLanguages) @@ -50,22 +46,36 @@ namespace SafeExamBrowser.SystemComponents Name = language.LayoutName }; - control.Add(layout); layouts.Add(layout); - - logger.Info($"Added keyboard layout {ToString(language)} to system control."); + logger.Info($"Detected keyboard layout {ToString(language)}."); } } + public void Register(ISystemKeyboardLayoutControl control) + { + control.LayoutSelected += Control_LayoutSelected; + control.SetTooltip(text.Get(TextKey.SystemControl_KeyboardLayoutTooltip)); + + foreach (var layout in layouts) + { + control.Add(layout); + } + + controls.Add(control); + } + public void Terminate() { - control?.Close(); - if (originalLanguage != null) { InputLanguage.CurrentInputLanguage = originalLanguage; logger.Info($"Restored original keyboard layout {ToString(originalLanguage)}."); } + + foreach (var control in controls) + { + control.Close(); + } } private void Control_LayoutSelected(IKeyboardLayout layout) diff --git a/SafeExamBrowser.SystemComponents/PowerSupply.cs b/SafeExamBrowser.SystemComponents/PowerSupply.cs index 7f660a1a..5990f205 100644 --- a/SafeExamBrowser.SystemComponents/PowerSupply.cs +++ b/SafeExamBrowser.SystemComponents/PowerSupply.cs @@ -7,6 +7,7 @@ */ using System; +using System.Collections.Generic; using System.Timers; using SafeExamBrowser.Contracts.I18n; using SafeExamBrowser.Contracts.Logging; @@ -23,22 +24,19 @@ namespace SafeExamBrowser.SystemComponents private bool infoShown, warningShown; private ILogger logger; - private ISystemPowerSupplyControl control; + private IList controls; private IText text; private Timer timer; public PowerSupply(ILogger logger, IText text) { + this.controls = new List(); this.logger = logger; this.text = text; } - public void Initialize(ISystemPowerSupplyControl control) + public void Initialize() { - this.control = control; - - UpdateControl(); - timer = new Timer(TWO_SECONDS); timer.Elapsed += Timer_Elapsed; timer.AutoReset = true; @@ -47,19 +45,32 @@ namespace SafeExamBrowser.SystemComponents logger.Info("Started monitoring the power supply."); } + public void Register(ISystemPowerSupplyControl control) + { + controls.Add(control); + UpdateControls(); + } + public void Terminate() { - timer?.Stop(); - control?.Close(); - logger.Info("Stopped monitoring the power supply."); + if (timer != null) + { + timer.Stop(); + logger.Info("Stopped monitoring the power supply."); + } + + foreach (var control in controls) + { + control.Close(); + } } private void Timer_Elapsed(object sender, ElapsedEventArgs e) { - UpdateControl(); + UpdateControls(); } - private void UpdateControl() + private void UpdateControls() { var charge = SystemInformation.PowerStatus.BatteryLifePercent; var percentage = Math.Round(charge * 100); @@ -67,32 +78,35 @@ namespace SafeExamBrowser.SystemComponents var online = SystemInformation.PowerStatus.PowerLineStatus == PowerLineStatus.Online; var tooltip = string.Empty; - if (online) + foreach (var control in controls) { - tooltip = text.Get(percentage == 100 ? TextKey.SystemControl_BatteryCharged : TextKey.SystemControl_BatteryCharging); - infoShown = false; - warningShown = false; + if (online) + { + tooltip = text.Get(percentage == 100 ? TextKey.SystemControl_BatteryCharged : TextKey.SystemControl_BatteryCharging); + infoShown = false; + warningShown = false; + } + else + { + var hours = SystemInformation.PowerStatus.BatteryLifeRemaining / 3600; + var minutes = (SystemInformation.PowerStatus.BatteryLifeRemaining - (hours * 3600)) / 60; + + HandleBatteryStatus(control, status); + + tooltip = text.Get(TextKey.SystemControl_BatteryRemainingCharge); + tooltip = tooltip.Replace("%%HOURS%%", hours.ToString()); + tooltip = tooltip.Replace("%%MINUTES%%", minutes.ToString()); + } + + tooltip = tooltip.Replace("%%CHARGE%%", percentage.ToString()); + + control.SetBatteryCharge(charge, status); + control.SetPowerGridConnection(online); + control.SetTooltip(tooltip); } - else - { - var hours = SystemInformation.PowerStatus.BatteryLifeRemaining / 3600; - var minutes = (SystemInformation.PowerStatus.BatteryLifeRemaining - (hours * 3600)) / 60; - - HandleBatteryStatus(status); - - tooltip = text.Get(TextKey.SystemControl_BatteryRemainingCharge); - tooltip = tooltip.Replace("%%HOURS%%", hours.ToString()); - tooltip = tooltip.Replace("%%MINUTES%%", minutes.ToString()); - } - - tooltip = tooltip.Replace("%%CHARGE%%", percentage.ToString()); - - control.SetBatteryCharge(charge, status); - control.SetPowerGridConnection(online); - control.SetTooltip(tooltip); } - private void HandleBatteryStatus(BatteryChargeStatus status) + private void HandleBatteryStatus(ISystemPowerSupplyControl control, BatteryChargeStatus status) { if (status == BatteryChargeStatus.Low && !infoShown) { diff --git a/SafeExamBrowser.SystemComponents/WirelessNetwork.cs b/SafeExamBrowser.SystemComponents/WirelessNetwork.cs index 31d519d4..58694d9d 100644 --- a/SafeExamBrowser.SystemComponents/WirelessNetwork.cs +++ b/SafeExamBrowser.SystemComponents/WirelessNetwork.cs @@ -25,38 +25,30 @@ namespace SafeExamBrowser.SystemComponents private const int TWO_SECONDS = 2000; private readonly object @lock = new object(); - private ISystemWirelessNetworkControl control; + private IList controls; + private IList networks; + private bool hasWifiAdapter; private ILogger logger; - private IList networks = new List(); private IText text; private Timer timer; private Wifi wifi; public WirelessNetwork(ILogger logger, IText text) { + this.controls = new List(); this.logger = logger; + this.networks = new List(); this.text = text; } - public void Initialize(ISystemWirelessNetworkControl control) + public void Initialize() { - this.control = control; - this.wifi = new Wifi(); + wifi = new Wifi(); + wifi.ConnectionStatusChanged += Wifi_ConnectionStatusChanged; + hasWifiAdapter = !wifi.NoWifiAvailable && !IsTurnedOff(); - if (wifi.NoWifiAvailable || IsTurnedOff()) + if (hasWifiAdapter) { - control.HasWirelessNetworkAdapter = false; - control.SetTooltip(text.Get(TextKey.SystemControl_WirelessNotAvailable)); - logger.Info("Wireless networks cannot be monitored, as there is no hardware adapter available or it is turned off."); - } - else - { - control.HasWirelessNetworkAdapter = true; - control.NetworkSelected += Control_NetworkSelected; - wifi.ConnectionStatusChanged += Wifi_ConnectionStatusChanged; - - UpdateControl(); - timer = new Timer(TWO_SECONDS); timer.Elapsed += Timer_Elapsed; timer.AutoReset = true; @@ -64,17 +56,45 @@ namespace SafeExamBrowser.SystemComponents logger.Info("Started monitoring the wireless network adapter."); } + else + { + logger.Info("Wireless networks cannot be monitored, as there is no hardware adapter available or it is turned off."); + } + } + + public void Register(ISystemWirelessNetworkControl control) + { + if (hasWifiAdapter) + { + control.HasWirelessNetworkAdapter = true; + control.NetworkSelected += Control_NetworkSelected; + } + else + { + control.HasWirelessNetworkAdapter = false; + control.SetTooltip(text.Get(TextKey.SystemControl_WirelessNotAvailable)); + } + + controls.Add(control); + + if (hasWifiAdapter) + { + UpdateControls(); + } } public void Terminate() { - timer?.Stop(); - control?.Close(); - if (timer != null) { + timer.Stop(); logger.Info("Stopped monitoring the wireless network adapter."); } + + foreach (var control in controls) + { + control.Close(); + } } private void Control_NetworkSelected(IWirelessNetwork network) @@ -85,7 +105,11 @@ namespace SafeExamBrowser.SystemComponents var authRequest = new AuthRequest(accessPoint); accessPoint.ConnectAsync(authRequest, false, (success) => AccessPoint_OnConnectComplete(network.Name, success)); - control.IsConnecting = true; + + foreach (var control in controls) + { + control.IsConnecting = true; + } } catch (Exception e) { @@ -104,18 +128,22 @@ namespace SafeExamBrowser.SystemComponents logger.Error($"Failed to connect to wireless network '{name}!'"); } - control.IsConnecting = false; - UpdateControl(); + foreach (var control in controls) + { + control.IsConnecting = false; + } + + UpdateControls(); } private void Timer_Elapsed(object sender, ElapsedEventArgs e) { - UpdateControl(); + UpdateControls(); } private void Wifi_ConnectionStatusChanged(object sender, WifiStatusEventArgs e) { - UpdateControl(); + UpdateControls(); } private bool IsTurnedOff() @@ -143,12 +171,15 @@ namespace SafeExamBrowser.SystemComponents return true; } - private void UpdateControl() + private void UpdateControls() { lock (@lock) { try { + var isConnected = false; + var networkName = string.Empty; + networks.Clear(); foreach (var accessPoint in wifi.GetAccessPoints()) @@ -156,22 +187,28 @@ namespace SafeExamBrowser.SystemComponents // The user may only connect to an already configured wireless network! if (accessPoint.HasProfile) { - networks.Add(ToDefinition(accessPoint)); + networkName = accessPoint.Name; + isConnected = accessPoint.IsConnected; - if (accessPoint.IsConnected) - { - control.SetTooltip(text.Get(TextKey.SystemControl_WirelessConnected).Replace("%%NAME%%", accessPoint.Name)); - } + networks.Add(ToDefinition(accessPoint)); } } - if (wifi.ConnectionStatus == WifiStatus.Disconnected) + foreach (var control in controls) { - control.SetTooltip(text.Get(TextKey.SystemControl_WirelessDisconnected)); - } + if (wifi.ConnectionStatus == WifiStatus.Disconnected) + { + control.SetTooltip(text.Get(TextKey.SystemControl_WirelessDisconnected)); + } - control.NetworkStatus = ToStatus(wifi.ConnectionStatus); - control.Update(new List(networks)); + if (isConnected) + { + control.SetTooltip(text.Get(TextKey.SystemControl_WirelessConnected).Replace("%%NAME%%", networkName)); + } + + control.NetworkStatus = ToStatus(wifi.ConnectionStatus); + control.Update(new List(networks)); + } } catch (Exception e) { diff --git a/SafeExamBrowser.UserInterface.Desktop/ActionCenter.xaml b/SafeExamBrowser.UserInterface.Desktop/ActionCenter.xaml index c0385db4..b3b84901 100644 --- a/SafeExamBrowser.UserInterface.Desktop/ActionCenter.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/ActionCenter.xaml @@ -20,14 +20,6 @@ - - - - - - - - - + diff --git a/SafeExamBrowser.UserInterface.Desktop/ActionCenter.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/ActionCenter.xaml.cs index 911442eb..7e953051 100644 --- a/SafeExamBrowser.UserInterface.Desktop/ActionCenter.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/ActionCenter.xaml.cs @@ -33,12 +33,18 @@ namespace SafeExamBrowser.UserInterface.Desktop public void AddNotificationControl(INotificationControl control) { - + if (control is UIElement uiElement) + { + ControlPanel.Children.Add(uiElement); + } } public void AddSystemControl(ISystemControl control) { - + if (control is UIElement uiElement) + { + ControlPanel.Children.Add(uiElement); + } } public new void Close() diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterNotificationButton.xaml b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterNotificationButton.xaml new file mode 100644 index 00000000..b8e093e7 --- /dev/null +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterNotificationButton.xaml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterNotificationButton.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterNotificationButton.xaml.cs new file mode 100644 index 00000000..b435ec99 --- /dev/null +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterNotificationButton.xaml.cs @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 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.Windows; +using System.Windows.Controls; +using SafeExamBrowser.Contracts.Client; +using SafeExamBrowser.Contracts.UserInterface.Shell; +using SafeExamBrowser.Contracts.UserInterface.Shell.Events; +using SafeExamBrowser.UserInterface.Desktop.Utilities; + +namespace SafeExamBrowser.UserInterface.Desktop.Controls +{ + public partial class ActionCenterNotificationButton : UserControl, INotificationControl + { + public event NotificationControlClickedEventHandler Clicked; + + public ActionCenterNotificationButton(INotificationInfo info) + { + InitializeComponent(); + InitializeNotificationIcon(info); + } + + private void Icon_Click(object sender, RoutedEventArgs e) + { + Clicked?.Invoke(); + } + + private void InitializeNotificationIcon(INotificationInfo info) + { + Icon.Content = IconResourceLoader.Load(info.IconResource); + IconButton.ToolTip = info.Tooltip; + Text.Text = info.Tooltip; + } + } +} diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/NotificationButton.xaml b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarNotificationButton.xaml similarity index 96% rename from SafeExamBrowser.UserInterface.Desktop/Controls/NotificationButton.xaml rename to SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarNotificationButton.xaml index fa95ab45..999bb92b 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/NotificationButton.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarNotificationButton.xaml @@ -1,4 +1,4 @@ - ActionCenterApplicationButton.xaml + + ActionCenterNotificationButton.xaml + TaskbarApplicationControl.xaml @@ -95,8 +98,8 @@ KeyboardLayoutControl.xaml - - NotificationButton.xaml + + TaskbarNotificationButton.xaml PowerSupplyControl.xaml @@ -151,6 +154,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile @@ -171,7 +178,7 @@ Designer MSBuild:Compile - + Designer MSBuild:Compile diff --git a/SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs b/SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs index 2253627f..bb9613cf 100644 --- a/SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs +++ b/SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs @@ -86,9 +86,16 @@ namespace SafeExamBrowser.UserInterface.Desktop return logWindow; } - public INotificationControl CreateNotificationControl(INotificationInfo info) + public INotificationControl CreateNotificationControl(INotificationInfo info, Location location) { - return new NotificationButton(info); + if (location == Location.ActionCenter) + { + return new ActionCenterNotificationButton(info); + } + else + { + return new TaskbarNotificationButton(info); + } } public IPasswordDialog CreatePasswordDialog(string message, string title)