From 519fb9e57b974088264b08768e535a826d0b0c2e Mon Sep 17 00:00:00 2001 From: dbuechel Date: Fri, 8 Mar 2019 11:43:52 +0100 Subject: [PATCH] SEBWIN-141: Implemented draft of application controls for action center. --- .../BrowserApplicationController.cs | 17 +++-- .../Notifications/NotificationButtonMock.cs | 6 +- .../Operations/BrowserOperationTests.cs | 38 +++++----- .../Operations/TaskbarOperationTests.cs | 5 +- SafeExamBrowser.Client/CompositionRoot.cs | 2 +- .../AboutNotificationController.cs | 4 +- .../LogNotificationController.cs | 4 +- .../Operations/ActionCenterOperation.cs | 33 +++++++-- .../Operations/BrowserOperation.cs | 12 +++- .../Operations/TaskbarOperation.cs | 8 +-- .../Applications/IApplicationController.cs | 4 +- .../Client/INotificationController.cs | 2 +- SafeExamBrowser.Contracts/I18n/TextKey.cs | 2 + .../SafeExamBrowser.Contracts.csproj | 9 +-- .../UserInterface/IUserInterfaceFactory.cs | 8 +-- ... ApplicationControlClickedEventHandler.cs} | 4 +- ...NotificationControlClickedEventHandler.cs} | 4 +- .../UserInterface/Shell/IActionCenter.cs | 22 ++++++ ...cationButton.cs => IApplicationControl.cs} | 12 ++-- ...ationButton.cs => INotificationControl.cs} | 8 +-- .../UserInterface/Shell/ITaskbar.cs | 8 +-- .../UserInterface/Shell/Location.cs | 26 +++++++ SafeExamBrowser.I18n/Text.xml | 6 ++ .../ActionCenter.xaml | 27 ++++++- .../ActionCenter.xaml.cs | 21 ++++++ .../ActionCenterApplicationButton.xaml | 24 +++++++ .../ActionCenterApplicationButton.xaml.cs | 66 +++++++++++++++++ .../ActionCenterApplicationControl.xaml | 29 ++++++++ .../ActionCenterApplicationControl.xaml.cs | 70 +++++++++++++++++++ .../Controls/NotificationButton.xaml.cs | 4 +- ...on.xaml => TaskbarApplicationControl.xaml} | 2 +- ...l.cs => TaskbarApplicationControl.xaml.cs} | 14 ++-- ... => TaskbarApplicationInstanceButton.xaml} | 2 +- ... TaskbarApplicationInstanceButton.xaml.cs} | 6 +- ...feExamBrowser.UserInterface.Desktop.csproj | 26 +++++-- .../Taskbar.xaml | 3 +- .../Taskbar.xaml.cs | 8 +-- .../Templates/Buttons.xaml | 30 ++++++-- .../UserInterfaceFactory.cs | 13 +++- 39 files changed, 474 insertions(+), 115 deletions(-) rename SafeExamBrowser.Contracts/UserInterface/Shell/Events/{ApplicationButtonClickedEventHandler.cs => ApplicationControlClickedEventHandler.cs} (68%) rename SafeExamBrowser.Contracts/UserInterface/Shell/Events/{NotificationButtonClickedEventHandler.cs => NotificationControlClickedEventHandler.cs} (81%) rename SafeExamBrowser.Contracts/UserInterface/Shell/{IApplicationButton.cs => IApplicationControl.cs} (55%) rename SafeExamBrowser.Contracts/UserInterface/Shell/{INotificationButton.cs => INotificationControl.cs} (66%) create mode 100644 SafeExamBrowser.Contracts/UserInterface/Shell/Location.cs create mode 100644 SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterApplicationButton.xaml create mode 100644 SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterApplicationButton.xaml.cs create mode 100644 SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterApplicationControl.xaml create mode 100644 SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterApplicationControl.xaml.cs rename SafeExamBrowser.UserInterface.Desktop/Controls/{ApplicationButton.xaml => TaskbarApplicationControl.xaml} (98%) rename SafeExamBrowser.UserInterface.Desktop/Controls/{ApplicationButton.xaml.cs => TaskbarApplicationControl.xaml.cs} (83%) rename SafeExamBrowser.UserInterface.Desktop/Controls/{ApplicationInstanceButton.xaml => TaskbarApplicationInstanceButton.xaml} (97%) rename SafeExamBrowser.UserInterface.Desktop/Controls/{ApplicationInstanceButton.xaml.cs => TaskbarApplicationInstanceButton.xaml.cs} (86%) diff --git a/SafeExamBrowser.Browser/BrowserApplicationController.cs b/SafeExamBrowser.Browser/BrowserApplicationController.cs index 23f1993c..70b3c2be 100644 --- a/SafeExamBrowser.Browser/BrowserApplicationController.cs +++ b/SafeExamBrowser.Browser/BrowserApplicationController.cs @@ -29,7 +29,7 @@ namespace SafeExamBrowser.Browser private int instanceIdCounter = default(int); private AppConfig appConfig; - private IApplicationButton button; + private IList controls; private IList instances; private IMessageBox messageBox; private IModuleLogger logger; @@ -48,6 +48,7 @@ namespace SafeExamBrowser.Browser IUserInterfaceFactory uiFactory) { this.appConfig = appConfig; + this.controls = new List(); this.instances = new List(); this.logger = logger; this.messageBox = messageBox; @@ -69,10 +70,10 @@ namespace SafeExamBrowser.Browser } } - public void RegisterApplicationButton(IApplicationButton button) + public void RegisterApplicationControl(IApplicationControl control) { - this.button = button; - this.button.Clicked += Button_OnClick; + control.Clicked += ApplicationControl_Clicked; + controls.Add(control); } public void Start() @@ -108,7 +109,11 @@ namespace SafeExamBrowser.Browser instance.PopupRequested += Instance_PopupRequested; instance.Terminated += Instance_Terminated; - button.RegisterInstance(instance); + foreach (var control in controls) + { + control.RegisterInstance(instance); + } + instances.Add(instance); instance.Window.Show(); @@ -135,7 +140,7 @@ namespace SafeExamBrowser.Browser return cefSettings; } - private void Button_OnClick(InstanceIdentifier id = null) + private void ApplicationControl_Clicked(InstanceIdentifier id = null) { if (id == null) { diff --git a/SafeExamBrowser.Client.UnitTests/Notifications/NotificationButtonMock.cs b/SafeExamBrowser.Client.UnitTests/Notifications/NotificationButtonMock.cs index a3e94eda..6b351d51 100644 --- a/SafeExamBrowser.Client.UnitTests/Notifications/NotificationButtonMock.cs +++ b/SafeExamBrowser.Client.UnitTests/Notifications/NotificationButtonMock.cs @@ -11,14 +11,14 @@ using SafeExamBrowser.Contracts.UserInterface.Shell.Events; namespace SafeExamBrowser.Client.UnitTests.Notifications { - class NotificationButtonMock : INotificationButton + class NotificationButtonMock : INotificationControl { - private NotificationButtonClickedEventHandler clicked; + private NotificationControlClickedEventHandler clicked; public bool HasSubscribed; public bool HasUnsubscribed; - public event NotificationButtonClickedEventHandler Clicked + public event NotificationControlClickedEventHandler Clicked { add { diff --git a/SafeExamBrowser.Client.UnitTests/Operations/BrowserOperationTests.cs b/SafeExamBrowser.Client.UnitTests/Operations/BrowserOperationTests.cs index fa9b6955..70a2eb7e 100644 --- a/SafeExamBrowser.Client.UnitTests/Operations/BrowserOperationTests.cs +++ b/SafeExamBrowser.Client.UnitTests/Operations/BrowserOperationTests.cs @@ -19,24 +19,26 @@ namespace SafeExamBrowser.Client.UnitTests.Operations [TestClass] public class BrowserOperationTests { - private Mock controllerMock; - private Mock appInfoMock; - private Mock loggerMock; - private Mock taskbarMock; - private Mock uiFactoryMock; + private Mock actionCenter; + private Mock controller; + private Mock appInfo; + private Mock logger; + private Mock taskbar; + private Mock uiFactory; private BrowserOperation sut; [TestInitialize] public void Initialize() { - controllerMock = new Mock(); - appInfoMock = new Mock(); - loggerMock = new Mock(); - taskbarMock = new Mock(); - uiFactoryMock = new Mock(); + actionCenter = new Mock(); + controller = new Mock(); + appInfo = new Mock(); + logger = new Mock(); + taskbar = new Mock(); + uiFactory = new Mock(); - sut = new BrowserOperation(controllerMock.Object, appInfoMock.Object, loggerMock.Object, taskbarMock.Object, uiFactoryMock.Object); + sut = new BrowserOperation(actionCenter.Object, controller.Object, appInfo.Object, logger.Object, taskbar.Object, uiFactory.Object); } [TestMethod] @@ -44,15 +46,15 @@ namespace SafeExamBrowser.Client.UnitTests.Operations { var order = 0; - controllerMock.Setup(c => c.Initialize()).Callback(() => Assert.AreEqual(++order, 1)); - controllerMock.Setup(c => c.RegisterApplicationButton(It.IsAny())).Callback(() => Assert.AreEqual(++order, 2)); - taskbarMock.Setup(t => t.AddApplication(It.IsAny())).Callback(() => Assert.AreEqual(++order, 3)); + 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(); - controllerMock.Verify(c => c.Initialize(), Times.Once); - controllerMock.Verify(c => c.RegisterApplicationButton(It.IsAny()), Times.Once); - taskbarMock.Verify(t => t.AddApplication(It.IsAny()), Times.Once); + controller.Verify(c => c.Initialize(), Times.Once); + controller.Verify(c => c.RegisterApplicationControl(It.IsAny()), Times.Once); + taskbar.Verify(t => t.AddApplicationControl(It.IsAny()), Times.Once); } [TestMethod] @@ -60,7 +62,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations { sut.Revert(); - controllerMock.Verify(c => c.Terminate(), Times.Once); + controller.Verify(c => c.Terminate(), Times.Once); } } } diff --git a/SafeExamBrowser.Client.UnitTests/Operations/TaskbarOperationTests.cs b/SafeExamBrowser.Client.UnitTests/Operations/TaskbarOperationTests.cs index 61f5df9f..41d10e5d 100644 --- a/SafeExamBrowser.Client.UnitTests/Operations/TaskbarOperationTests.cs +++ b/SafeExamBrowser.Client.UnitTests/Operations/TaskbarOperationTests.cs @@ -11,7 +11,6 @@ using Moq; using SafeExamBrowser.Client.Operations; using SafeExamBrowser.Contracts.Client; using SafeExamBrowser.Contracts.Configuration.Settings; -using SafeExamBrowser.Contracts.I18n; using SafeExamBrowser.Contracts.Logging; using SafeExamBrowser.Contracts.SystemComponents; using SafeExamBrowser.Contracts.UserInterface; @@ -58,7 +57,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations settings.AllowWirelessNetwork = true; settings.EnableTaskbar = true; systemInfoMock.SetupGet(s => s.HasBattery).Returns(true); - uiFactoryMock.Setup(u => u.CreateNotification(It.IsAny())).Returns(new Mock().Object); + uiFactoryMock.Setup(u => u.CreateNotificationControl(It.IsAny())).Returns(new Mock().Object); sut = new TaskbarOperation( loggerMock.Object, @@ -84,7 +83,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations powerSupplyMock.Verify(p => p.Initialize(It.IsAny()), Times.Once); wirelessNetworkMock.Verify(w => w.Initialize(It.IsAny()), Times.Once); taskbarMock.Verify(t => t.AddSystemControl(It.IsAny()), Times.Exactly(3)); - taskbarMock.Verify(t => t.AddNotification(It.IsAny()), Times.Exactly(2)); + taskbarMock.Verify(t => t.AddNotificationControl(It.IsAny()), Times.Exactly(2)); } [TestMethod] diff --git a/SafeExamBrowser.Client/CompositionRoot.cs b/SafeExamBrowser.Client/CompositionRoot.cs index a9892313..25af166c 100644 --- a/SafeExamBrowser.Client/CompositionRoot.cs +++ b/SafeExamBrowser.Client/CompositionRoot.cs @@ -230,7 +230,7 @@ namespace SafeExamBrowser.Client var moduleLogger = new ModuleLogger(logger, "BrowserController"); var browserController = new BrowserApplicationController(configuration.AppConfig, configuration.Settings.Browser, messageBox, moduleLogger, text, uiFactory); var browserInfo = new BrowserApplicationInfo(); - var operation = new BrowserOperation(browserController, browserInfo, logger, taskbar, uiFactory); + var operation = new BrowserOperation(actionCenter, browserController, browserInfo, logger, taskbar, uiFactory); this.browserController = browserController; diff --git a/SafeExamBrowser.Client/Notifications/AboutNotificationController.cs b/SafeExamBrowser.Client/Notifications/AboutNotificationController.cs index 96e3f5aa..d613e2f7 100644 --- a/SafeExamBrowser.Client/Notifications/AboutNotificationController.cs +++ b/SafeExamBrowser.Client/Notifications/AboutNotificationController.cs @@ -16,7 +16,7 @@ namespace SafeExamBrowser.Client.Notifications { internal class AboutNotificationController : INotificationController { - private INotificationButton notification; + private INotificationControl notification; private AppConfig appConfig; private IUserInterfaceFactory uiFactory; private IWindow window; @@ -27,7 +27,7 @@ namespace SafeExamBrowser.Client.Notifications this.uiFactory = uiFactory; } - public void RegisterNotification(INotificationButton notification) + public void RegisterNotification(INotificationControl notification) { this.notification = notification; diff --git a/SafeExamBrowser.Client/Notifications/LogNotificationController.cs b/SafeExamBrowser.Client/Notifications/LogNotificationController.cs index 52093e68..57a52ee2 100644 --- a/SafeExamBrowser.Client/Notifications/LogNotificationController.cs +++ b/SafeExamBrowser.Client/Notifications/LogNotificationController.cs @@ -16,7 +16,7 @@ namespace SafeExamBrowser.Client.Notifications { internal class LogNotificationController : INotificationController { - private INotificationButton notification; + private INotificationControl notification; private ILogger logger; private IUserInterfaceFactory uiFactory; private IWindow window; @@ -27,7 +27,7 @@ namespace SafeExamBrowser.Client.Notifications this.uiFactory = uiFactory; } - public void RegisterNotification(INotificationButton notification) + public void RegisterNotification(INotificationControl notification) { this.notification = notification; diff --git a/SafeExamBrowser.Client/Operations/ActionCenterOperation.cs b/SafeExamBrowser.Client/Operations/ActionCenterOperation.cs index 31f8aacf..b40ad0b8 100644 --- a/SafeExamBrowser.Client/Operations/ActionCenterOperation.cs +++ b/SafeExamBrowser.Client/Operations/ActionCenterOperation.cs @@ -11,6 +11,7 @@ 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; @@ -69,10 +70,21 @@ namespace SafeExamBrowser.Client.Operations public OperationResult Perform() { - foreach (var activator in activators) + StatusChanged?.Invoke(TextKey.OperationStatus_InitializeActionCenter); + + if (settings.EnableActionCenter) { - actionCenter.Register(activator); - activator.Start(); + 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; @@ -80,9 +92,20 @@ namespace SafeExamBrowser.Client.Operations public OperationResult Revert() { - foreach (var activator in activators) + StatusChanged?.Invoke(TextKey.OperationStatus_TerminateActionCenter); + + if (settings.EnableActionCenter) { - activator.Stop(); + 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/BrowserOperation.cs b/SafeExamBrowser.Client/Operations/BrowserOperation.cs index b372c63e..d3410584 100644 --- a/SafeExamBrowser.Client/Operations/BrowserOperation.cs +++ b/SafeExamBrowser.Client/Operations/BrowserOperation.cs @@ -18,6 +18,7 @@ namespace SafeExamBrowser.Client.Operations { internal class BrowserOperation : IOperation { + private IActionCenter actionCenter; private IApplicationController browserController; private IApplicationInfo browserInfo; private ILogger logger; @@ -28,12 +29,14 @@ namespace SafeExamBrowser.Client.Operations public event StatusChangedEventHandler StatusChanged; public BrowserOperation( + IActionCenter actionCenter, IApplicationController browserController, IApplicationInfo browserInfo, ILogger logger, ITaskbar taskbar, IUserInterfaceFactory uiFactory) { + this.actionCenter = actionCenter; this.browserController = browserController; this.browserInfo = browserInfo; this.logger = logger; @@ -46,12 +49,15 @@ namespace SafeExamBrowser.Client.Operations logger.Info("Initializing browser..."); StatusChanged?.Invoke(TextKey.OperationStatus_InitializeBrowser); - var browserButton = uiFactory.CreateApplicationButton(browserInfo); + var actionCenterControl = uiFactory.CreateApplicationControl(browserInfo, Location.ActionCenter); + var taskbarControl = uiFactory.CreateApplicationControl(browserInfo, Location.Taskbar); browserController.Initialize(); - browserController.RegisterApplicationButton(browserButton); + browserController.RegisterApplicationControl(actionCenterControl); + browserController.RegisterApplicationControl(taskbarControl); - taskbar.AddApplication(browserButton); + actionCenter.AddApplicationControl(actionCenterControl); + taskbar.AddApplicationControl(taskbarControl); return OperationResult.Success; } diff --git a/SafeExamBrowser.Client/Operations/TaskbarOperation.cs b/SafeExamBrowser.Client/Operations/TaskbarOperation.cs index dec4aee1..2c2ec455 100644 --- a/SafeExamBrowser.Client/Operations/TaskbarOperation.cs +++ b/SafeExamBrowser.Client/Operations/TaskbarOperation.cs @@ -142,10 +142,10 @@ namespace SafeExamBrowser.Client.Operations private void AddAboutNotification() { - var aboutNotification = uiFactory.CreateNotification(aboutInfo); + var aboutNotification = uiFactory.CreateNotificationControl(aboutInfo); aboutController.RegisterNotification(aboutNotification); - taskbar.AddNotification(aboutNotification); + taskbar.AddNotificationControl(aboutNotification); } private void AddKeyboardLayoutControl() @@ -158,10 +158,10 @@ namespace SafeExamBrowser.Client.Operations private void AddLogNotification() { - var logNotification = uiFactory.CreateNotification(logInfo); + var logNotification = uiFactory.CreateNotificationControl(logInfo); logController.RegisterNotification(logNotification); - taskbar.AddNotification(logNotification); + taskbar.AddNotificationControl(logNotification); } private void AddPowerSupplyControl() diff --git a/SafeExamBrowser.Contracts/Applications/IApplicationController.cs b/SafeExamBrowser.Contracts/Applications/IApplicationController.cs index 00877f43..f747f3d6 100644 --- a/SafeExamBrowser.Contracts/Applications/IApplicationController.cs +++ b/SafeExamBrowser.Contracts/Applications/IApplicationController.cs @@ -21,9 +21,9 @@ namespace SafeExamBrowser.Contracts.Applications void Initialize(); /// - /// Registers the taskbar button for this application. + /// Registers an application control for this application. /// - void RegisterApplicationButton(IApplicationButton button); + void RegisterApplicationControl(IApplicationControl control); /// /// Starts the execution of the application. diff --git a/SafeExamBrowser.Contracts/Client/INotificationController.cs b/SafeExamBrowser.Contracts/Client/INotificationController.cs index be847fe5..ba9d3863 100644 --- a/SafeExamBrowser.Contracts/Client/INotificationController.cs +++ b/SafeExamBrowser.Contracts/Client/INotificationController.cs @@ -18,7 +18,7 @@ namespace SafeExamBrowser.Contracts.Client /// /// Registers the taskbar notification. /// - void RegisterNotification(INotificationButton notification); + void RegisterNotification(INotificationControl notification); /// /// Instructs the controller to shut down and release all used resources. diff --git a/SafeExamBrowser.Contracts/I18n/TextKey.cs b/SafeExamBrowser.Contracts/I18n/TextKey.cs index 2e2bd662..8ede288c 100644 --- a/SafeExamBrowser.Contracts/I18n/TextKey.cs +++ b/SafeExamBrowser.Contracts/I18n/TextKey.cs @@ -56,6 +56,7 @@ namespace SafeExamBrowser.Contracts.I18n OperationStatus_CloseRuntimeConnection, OperationStatus_EmptyClipboard, OperationStatus_FinalizeServiceSession, + OperationStatus_InitializeActionCenter, OperationStatus_InitializeBrowser, OperationStatus_InitializeClient, OperationStatus_InitializeConfiguration, @@ -80,6 +81,7 @@ namespace SafeExamBrowser.Contracts.I18n OperationStatus_StopMouseInterception, OperationStatus_StopProcessMonitoring, OperationStatus_StopWindowMonitoring, + OperationStatus_TerminateActionCenter, OperationStatus_TerminateBrowser, OperationStatus_TerminateTaskbar, OperationStatus_WaitExplorerStartup, diff --git a/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj b/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj index b30f3897..b7d15f4e 100644 --- a/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj +++ b/SafeExamBrowser.Contracts/SafeExamBrowser.Contracts.csproj @@ -188,11 +188,12 @@ - + - + + @@ -200,7 +201,7 @@ - + @@ -209,7 +210,7 @@ - + diff --git a/SafeExamBrowser.Contracts/UserInterface/IUserInterfaceFactory.cs b/SafeExamBrowser.Contracts/UserInterface/IUserInterfaceFactory.cs index c838a8af..d12a2744 100644 --- a/SafeExamBrowser.Contracts/UserInterface/IUserInterfaceFactory.cs +++ b/SafeExamBrowser.Contracts/UserInterface/IUserInterfaceFactory.cs @@ -31,9 +31,9 @@ namespace SafeExamBrowser.Contracts.UserInterface IWindow CreateAboutWindow(AppConfig appConfig); /// - /// Creates a taskbar button, initialized with the given application information. + /// Creates an application control for the specified location, initialized with the given application information. /// - IApplicationButton CreateApplicationButton(IApplicationInfo info); + IApplicationControl CreateApplicationControl(IApplicationInfo info, Location location); /// /// Creates a new browser window loaded with the given browser control and settings. @@ -51,9 +51,9 @@ namespace SafeExamBrowser.Contracts.UserInterface IWindow CreateLogWindow(ILogger logger); /// - /// Creates a taskbar notification, initialized with the given notification information. + /// Creates a notification control, initialized with the given notification information. /// - INotificationButton CreateNotification(INotificationInfo info); + INotificationControl CreateNotificationControl(INotificationInfo info); /// /// Creates a password dialog with the given message and title. diff --git a/SafeExamBrowser.Contracts/UserInterface/Shell/Events/ApplicationButtonClickedEventHandler.cs b/SafeExamBrowser.Contracts/UserInterface/Shell/Events/ApplicationControlClickedEventHandler.cs similarity index 68% rename from SafeExamBrowser.Contracts/UserInterface/Shell/Events/ApplicationButtonClickedEventHandler.cs rename to SafeExamBrowser.Contracts/UserInterface/Shell/Events/ApplicationControlClickedEventHandler.cs index a4bf9c11..bda0e2c0 100644 --- a/SafeExamBrowser.Contracts/UserInterface/Shell/Events/ApplicationButtonClickedEventHandler.cs +++ b/SafeExamBrowser.Contracts/UserInterface/Shell/Events/ApplicationControlClickedEventHandler.cs @@ -11,8 +11,8 @@ using SafeExamBrowser.Contracts.Applications; namespace SafeExamBrowser.Contracts.UserInterface.Shell.Events { /// - /// Indicates that an has been clicked, optionally specifying the ID of the selected instance (if + /// Indicates that an has been clicked, optionally specifying the identifier of the selected instance (if /// multiple instances of the same application are running). /// - public delegate void ApplicationButtonClickedEventHandler(InstanceIdentifier id = null); + public delegate void ApplicationControlClickedEventHandler(InstanceIdentifier id = null); } diff --git a/SafeExamBrowser.Contracts/UserInterface/Shell/Events/NotificationButtonClickedEventHandler.cs b/SafeExamBrowser.Contracts/UserInterface/Shell/Events/NotificationControlClickedEventHandler.cs similarity index 81% rename from SafeExamBrowser.Contracts/UserInterface/Shell/Events/NotificationButtonClickedEventHandler.cs rename to SafeExamBrowser.Contracts/UserInterface/Shell/Events/NotificationControlClickedEventHandler.cs index 8fef8ab6..2a41f39e 100644 --- a/SafeExamBrowser.Contracts/UserInterface/Shell/Events/NotificationButtonClickedEventHandler.cs +++ b/SafeExamBrowser.Contracts/UserInterface/Shell/Events/NotificationControlClickedEventHandler.cs @@ -9,7 +9,7 @@ namespace SafeExamBrowser.Contracts.UserInterface.Shell.Events { /// - /// Indicates that the user clicked on a in the . + /// Indicates that the user clicked on a in the shell. /// - public delegate void NotificationButtonClickedEventHandler(); + public delegate void NotificationControlClickedEventHandler(); } diff --git a/SafeExamBrowser.Contracts/UserInterface/Shell/IActionCenter.cs b/SafeExamBrowser.Contracts/UserInterface/Shell/IActionCenter.cs index e50baa65..589ef06c 100644 --- a/SafeExamBrowser.Contracts/UserInterface/Shell/IActionCenter.cs +++ b/SafeExamBrowser.Contracts/UserInterface/Shell/IActionCenter.cs @@ -6,6 +6,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +using SafeExamBrowser.Contracts.UserInterface.Shell.Events; + namespace SafeExamBrowser.Contracts.UserInterface.Shell { /// @@ -13,6 +15,26 @@ namespace SafeExamBrowser.Contracts.UserInterface.Shell /// public interface IActionCenter { + /// + /// Event fired when the user clicked the quit button. + /// + event QuitButtonClickedEventHandler QuitButtonClicked; + + /// + /// Adds the given application control to the action center. + /// + void AddApplicationControl(IApplicationControl control); + + /// + /// Adds the given notification control to the action center. + /// + void AddNotificationControl(INotificationControl control); + + /// + /// Adds the given system control to the action center. + /// + void AddSystemControl(ISystemControl control); + /// /// Closes the action center. /// diff --git a/SafeExamBrowser.Contracts/UserInterface/Shell/IApplicationButton.cs b/SafeExamBrowser.Contracts/UserInterface/Shell/IApplicationControl.cs similarity index 55% rename from SafeExamBrowser.Contracts/UserInterface/Shell/IApplicationButton.cs rename to SafeExamBrowser.Contracts/UserInterface/Shell/IApplicationControl.cs index 5d9a2ffe..d78fd6f0 100644 --- a/SafeExamBrowser.Contracts/UserInterface/Shell/IApplicationButton.cs +++ b/SafeExamBrowser.Contracts/UserInterface/Shell/IApplicationControl.cs @@ -12,18 +12,18 @@ using SafeExamBrowser.Contracts.UserInterface.Shell.Events; namespace SafeExamBrowser.Contracts.UserInterface.Shell { /// - /// The button of a (third-party) application which can be loaded into the . + /// The control for a (third-party) application which can be loaded into the shell. /// - public interface IApplicationButton + public interface IApplicationControl { /// - /// Event fired when the user clicked on the application button. If multiple instances of an application are active, - /// the handler is only executed when the user selects one of the instances. + /// Event fired when the user clicked on the application control. If multiple instances of an application are active, + /// the handler should only executed when the user selects one of the instances. /// - event ApplicationButtonClickedEventHandler Clicked; + event ApplicationControlClickedEventHandler Clicked; /// - /// Registers a new instance of an application, to be started / displayed if the user clicked the taskbar button. + /// Registers a new instance of an application to be accessed via the application control. /// void RegisterInstance(IApplicationInstance instance); } diff --git a/SafeExamBrowser.Contracts/UserInterface/Shell/INotificationButton.cs b/SafeExamBrowser.Contracts/UserInterface/Shell/INotificationControl.cs similarity index 66% rename from SafeExamBrowser.Contracts/UserInterface/Shell/INotificationButton.cs rename to SafeExamBrowser.Contracts/UserInterface/Shell/INotificationControl.cs index 1c065c3b..48ff13d6 100644 --- a/SafeExamBrowser.Contracts/UserInterface/Shell/INotificationButton.cs +++ b/SafeExamBrowser.Contracts/UserInterface/Shell/INotificationControl.cs @@ -11,13 +11,13 @@ using SafeExamBrowser.Contracts.UserInterface.Shell.Events; namespace SafeExamBrowser.Contracts.UserInterface.Shell { /// - /// The button of a notification which can be loaded into the . + /// The control for a notification which can be loaded into the shell. /// - public interface INotificationButton + public interface INotificationControl { /// - /// Event fired when the user clicked on the notification icon. + /// Event fired when the user clicked on the notification control. /// - event NotificationButtonClickedEventHandler Clicked; + event NotificationControlClickedEventHandler Clicked; } } diff --git a/SafeExamBrowser.Contracts/UserInterface/Shell/ITaskbar.cs b/SafeExamBrowser.Contracts/UserInterface/Shell/ITaskbar.cs index fd1b8716..57c3c6da 100644 --- a/SafeExamBrowser.Contracts/UserInterface/Shell/ITaskbar.cs +++ b/SafeExamBrowser.Contracts/UserInterface/Shell/ITaskbar.cs @@ -26,14 +26,14 @@ namespace SafeExamBrowser.Contracts.UserInterface.Shell event QuitButtonClickedEventHandler QuitButtonClicked; /// - /// Adds the given application button to the taskbar. + /// Adds the given application control to the taskbar. /// - void AddApplication(IApplicationButton button); + void AddApplicationControl(IApplicationControl control); /// - /// Adds the given notification button to the taskbar. + /// Adds the given notification control to the taskbar. /// - void AddNotification(INotificationButton button); + void AddNotificationControl(INotificationControl control); /// /// Adds the given system control to the taskbar. diff --git a/SafeExamBrowser.Contracts/UserInterface/Shell/Location.cs b/SafeExamBrowser.Contracts/UserInterface/Shell/Location.cs new file mode 100644 index 00000000..7bbebcc8 --- /dev/null +++ b/SafeExamBrowser.Contracts/UserInterface/Shell/Location.cs @@ -0,0 +1,26 @@ +/* + * 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/. + */ + +namespace SafeExamBrowser.Contracts.UserInterface.Shell +{ + /// + /// Defines all possible locations of a user control in the shell. + /// + public enum Location + { + /// + /// A user control styled for and placed in the action center. + /// + ActionCenter, + + /// + /// A user control styled for and placed in the taskbar. + /// + Taskbar + } +} diff --git a/SafeExamBrowser.I18n/Text.xml b/SafeExamBrowser.I18n/Text.xml index adf381fe..861b0555 100644 --- a/SafeExamBrowser.I18n/Text.xml +++ b/SafeExamBrowser.I18n/Text.xml @@ -126,6 +126,9 @@ Finalizing service session + + Initializing action center + Initializing browser @@ -198,6 +201,9 @@ Stopping window monitoring + + Terminating action center + Terminating browser diff --git a/SafeExamBrowser.UserInterface.Desktop/ActionCenter.xaml b/SafeExamBrowser.UserInterface.Desktop/ActionCenter.xaml index a81b676a..c0385db4 100644 --- a/SafeExamBrowser.UserInterface.Desktop/ActionCenter.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/ActionCenter.xaml @@ -4,9 +4,30 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop" - mc:Ignorable="d" Title="ActionCenter" Height="1000" Width="400" Background="#EEF0F0F0" AllowsTransparency="True" WindowStyle="None" - Topmost="True" ResizeMode="NoResize"> + mc:Ignorable="d" Title="ActionCenter" Height="1000" Width="400" Background="#EEF0F0F0" AllowsTransparency="True" WindowStyle="None" Topmost="True" ResizeMode="NoResize"> + + + + + + + - + + + + + + + + + + + + + + + + diff --git a/SafeExamBrowser.UserInterface.Desktop/ActionCenter.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/ActionCenter.xaml.cs index 1255b51f..911442eb 100644 --- a/SafeExamBrowser.UserInterface.Desktop/ActionCenter.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/ActionCenter.xaml.cs @@ -10,16 +10,37 @@ using System; using System.Windows; using System.Windows.Media.Animation; using SafeExamBrowser.Contracts.UserInterface.Shell; +using SafeExamBrowser.Contracts.UserInterface.Shell.Events; namespace SafeExamBrowser.UserInterface.Desktop { public partial class ActionCenter : Window, IActionCenter { + public event QuitButtonClickedEventHandler QuitButtonClicked; + public ActionCenter() { InitializeComponent(); } + public void AddApplicationControl(IApplicationControl control) + { + if (control is UIElement uiElement) + { + ApplicationPanel.Children.Add(uiElement); + } + } + + public void AddNotificationControl(INotificationControl control) + { + + } + + public void AddSystemControl(ISystemControl control) + { + + } + public new void Close() { Dispatcher.Invoke(base.Close); diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterApplicationButton.xaml b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterApplicationButton.xaml new file mode 100644 index 00000000..555c132f --- /dev/null +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterApplicationButton.xaml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterApplicationButton.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterApplicationButton.xaml.cs new file mode 100644 index 00000000..89d6efd4 --- /dev/null +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterApplicationButton.xaml.cs @@ -0,0 +1,66 @@ +/* + * 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.Applications; +using SafeExamBrowser.Contracts.Core; +using SafeExamBrowser.Contracts.UserInterface.Shell.Events; +using SafeExamBrowser.UserInterface.Desktop.Utilities; + +namespace SafeExamBrowser.UserInterface.Desktop.Controls +{ + public partial class ActionCenterApplicationButton : UserControl + { + private IApplicationInfo info; + private IApplicationInstance instance; + + internal event ApplicationControlClickedEventHandler Clicked; + + public ActionCenterApplicationButton(IApplicationInfo info, IApplicationInstance instance = null) + { + this.info = info; + this.instance = instance; + + InitializeComponent(); + InitializeApplicationInstanceButton(); + } + + private void InitializeApplicationInstanceButton() + { + Icon.Content = IconResourceLoader.Load(info.IconResource); + Text.Text = instance?.Name ?? info.Name; + Button.ToolTip = instance?.Name ?? info.Tooltip; + + if (instance != null) + { + instance.IconChanged += Instance_IconChanged; + instance.NameChanged += Instance_NameChanged; + } + } + + private void Instance_IconChanged(IIconResource icon) + { + Dispatcher.InvokeAsync(() => Icon.Content = IconResourceLoader.Load(icon)); + } + + private void Instance_NameChanged(string name) + { + Dispatcher.Invoke(() => + { + Text.Text = name; + Button.ToolTip = name; + }); + } + + private void Button_Click(object sender, RoutedEventArgs e) + { + Clicked?.Invoke(instance?.Id); + } + } +} diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterApplicationControl.xaml b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterApplicationControl.xaml new file mode 100644 index 00000000..37ec1158 --- /dev/null +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterApplicationControl.xaml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterApplicationControl.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterApplicationControl.xaml.cs new file mode 100644 index 00000000..25526b32 --- /dev/null +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterApplicationControl.xaml.cs @@ -0,0 +1,70 @@ +/* + * 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.Applications; +using SafeExamBrowser.Contracts.UserInterface.Shell; +using SafeExamBrowser.Contracts.UserInterface.Shell.Events; +using SafeExamBrowser.UserInterface.Desktop.Utilities; + +namespace SafeExamBrowser.UserInterface.Desktop.Controls +{ + public partial class ActionCenterApplicationControl : UserControl, IApplicationControl + { + private IApplicationInfo info; + + public event ApplicationControlClickedEventHandler Clicked; + + public ActionCenterApplicationControl(IApplicationInfo info) + { + this.info = info; + + InitializeComponent(); + InitializeApplicationControl(info); + } + + public void RegisterInstance(IApplicationInstance instance) + { + Dispatcher.Invoke(() => + { + var button = new ActionCenterApplicationButton(info, instance); + + button.Clicked += (id) => Clicked?.Invoke(id); + instance.Terminated += (id) => Instance_OnTerminated(id, button); + InstancePanel.Children.Add(button); + + ApplicationName.Visibility = Visibility.Visible; + ApplicationButton.Visibility = Visibility.Collapsed; + }); + } + + private void InitializeApplicationControl(IApplicationInfo info) + { + var button = new ActionCenterApplicationButton(info); + + button.Button.Click += (o, args) => Clicked?.Invoke(); + ApplicationName.Text = info.Name; + ApplicationButton.Content = button; + } + + private void Instance_OnTerminated(InstanceIdentifier id, ActionCenterApplicationButton button) + { + Dispatcher.InvokeAsync(() => + { + InstancePanel.Children.Remove(button); + + if (InstancePanel.Children.Count == 0) + { + ApplicationName.Visibility = Visibility.Collapsed; + ApplicationButton.Visibility = Visibility.Visible; + } + }); + } + } +} diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/NotificationButton.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/NotificationButton.xaml.cs index 3c336fa8..e4e6ba9e 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/NotificationButton.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/NotificationButton.xaml.cs @@ -15,9 +15,9 @@ using SafeExamBrowser.UserInterface.Desktop.Utilities; namespace SafeExamBrowser.UserInterface.Desktop.Controls { - public partial class NotificationButton : UserControl, INotificationButton + public partial class NotificationButton : UserControl, INotificationControl { - public event NotificationButtonClickedEventHandler Clicked; + public event NotificationControlClickedEventHandler Clicked; public NotificationButton(INotificationInfo info) { diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ApplicationButton.xaml b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarApplicationControl.xaml similarity index 98% rename from SafeExamBrowser.UserInterface.Desktop/Controls/ApplicationButton.xaml rename to SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarApplicationControl.xaml index ffc20df2..4058d154 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/ApplicationButton.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarApplicationControl.xaml @@ -1,4 +1,4 @@ - instances = new List(); - public event ApplicationButtonClickedEventHandler Clicked; + public event ApplicationControlClickedEventHandler Clicked; - public ApplicationButton(IApplicationInfo info) + public TaskbarApplicationControl(IApplicationInfo info) { this.info = info; InitializeComponent(); - InitializeApplicationButton(); + InitializeApplicationControl(); } public void RegisterInstance(IApplicationInstance instance) { Dispatcher.Invoke(() => { - var instanceButton = new ApplicationInstanceButton(instance, info); + var instanceButton = new TaskbarApplicationInstanceButton(instance, info); instanceButton.Clicked += (id) => Clicked?.Invoke(id); instance.Terminated += (id) => Instance_OnTerminated(id, instanceButton); @@ -49,7 +49,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls }); } - private void InitializeApplicationButton() + private void InitializeApplicationControl() { var originalBrush = Button.Background; @@ -85,7 +85,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls } } - private void Instance_OnTerminated(InstanceIdentifier id, ApplicationInstanceButton instanceButton) + private void Instance_OnTerminated(InstanceIdentifier id, TaskbarApplicationInstanceButton instanceButton) { Dispatcher.InvokeAsync(() => { diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ApplicationInstanceButton.xaml b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarApplicationInstanceButton.xaml similarity index 97% rename from SafeExamBrowser.UserInterface.Desktop/Controls/ApplicationInstanceButton.xaml rename to SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarApplicationInstanceButton.xaml index 99ed13b9..396f0063 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/ApplicationInstanceButton.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarApplicationInstanceButton.xaml @@ -1,4 +1,4 @@ - BrowserWindow.xaml - - ApplicationButton.xaml + + ActionCenterApplicationControl.xaml - - ApplicationInstanceButton.xaml + + ActionCenterApplicationButton.xaml + + + TaskbarApplicationControl.xaml + + + TaskbarApplicationInstanceButton.xaml DateTimeControl.xaml @@ -137,11 +143,19 @@ Designer MSBuild:Compile - + Designer MSBuild:Compile - + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + Designer MSBuild:Compile diff --git a/SafeExamBrowser.UserInterface.Desktop/Taskbar.xaml b/SafeExamBrowser.UserInterface.Desktop/Taskbar.xaml index 5e976ef7..4acd3be5 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Taskbar.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/Taskbar.xaml @@ -21,8 +21,7 @@ - + diff --git a/SafeExamBrowser.UserInterface.Desktop/Taskbar.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Taskbar.xaml.cs index e922d75e..aaf719ce 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Taskbar.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Taskbar.xaml.cs @@ -38,17 +38,17 @@ namespace SafeExamBrowser.UserInterface.Desktop QuitButton.Clicked += QuitButton_Clicked; } - public void AddApplication(IApplicationButton button) + public void AddApplicationControl(IApplicationControl control) { - if (button is UIElement uiElement) + if (control is UIElement uiElement) { ApplicationStackPanel.Children.Add(uiElement); } } - public void AddNotification(INotificationButton button) + public void AddNotificationControl(INotificationControl control) { - if (button is UIElement uiElement) + if (control is UIElement uiElement) { NotificationStackPanel.Children.Add(uiElement); } diff --git a/SafeExamBrowser.UserInterface.Desktop/Templates/Buttons.xaml b/SafeExamBrowser.UserInterface.Desktop/Templates/Buttons.xaml index b7b9b189..823e3cd2 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Templates/Buttons.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/Templates/Buttons.xaml @@ -3,27 +3,25 @@ - - + + - + - + - + @@ -42,4 +40,22 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs b/SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs index 387318d0..2253627f 100644 --- a/SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs +++ b/SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs @@ -40,9 +40,16 @@ namespace SafeExamBrowser.UserInterface.Desktop return new AboutWindow(appConfig, text); } - public IApplicationButton CreateApplicationButton(IApplicationInfo info) + public IApplicationControl CreateApplicationControl(IApplicationInfo info, Location location) { - return new ApplicationButton(info); + if (location == Location.ActionCenter) + { + return new ActionCenterApplicationControl(info); + } + else + { + return new TaskbarApplicationControl(info); + } } public IBrowserWindow CreateBrowserWindow(IBrowserControl control, BrowserSettings settings, bool isMainWindow) @@ -79,7 +86,7 @@ namespace SafeExamBrowser.UserInterface.Desktop return logWindow; } - public INotificationButton CreateNotification(INotificationInfo info) + public INotificationControl CreateNotificationControl(INotificationInfo info) { return new NotificationButton(info); }