diff --git a/SafeExamBrowser.Client/Operations/ShellOperation.cs b/SafeExamBrowser.Client/Operations/ShellOperation.cs index 5855d0d6..9c399960 100644 --- a/SafeExamBrowser.Client/Operations/ShellOperation.cs +++ b/SafeExamBrowser.Client/Operations/ShellOperation.cs @@ -110,21 +110,6 @@ namespace SafeExamBrowser.Client.Operations InitializeWirelessNetworkForActionCenter(); InitializePowerSupplyForActionCenter(); - //if (settings.AllowKeyboardLayout) - //{ - // AddKeyboardLayoutControl(); - //} - - //if (settings.AllowWirelessNetwork) - //{ - // AddWirelessNetworkControl(); - //} - - //if (systemInfo.HasBattery) - //{ - // AddPowerSupplyControl(); - //} - foreach (var activator in activators) { actionCenter.Register(activator); @@ -235,14 +220,20 @@ namespace SafeExamBrowser.Client.Operations private void InitializePowerSupplyForActionCenter() { - // TODO + if (systemInfo.HasBattery) + { + var control = uiFactory.CreatePowerSupplyControl(Location.ActionCenter); + + powerSupply.Register(control); + actionCenter.AddSystemControl(control); + } } private void InitializePowerSupplyForTaskbar() { if (systemInfo.HasBattery) { - var control = uiFactory.CreatePowerSupplyControl(); + var control = uiFactory.CreatePowerSupplyControl(Location.Taskbar); powerSupply.Register(control); taskbar.AddSystemControl(control); diff --git a/SafeExamBrowser.Contracts/UserInterface/IUserInterfaceFactory.cs b/SafeExamBrowser.Contracts/UserInterface/IUserInterfaceFactory.cs index a5d4b604..30ec82d2 100644 --- a/SafeExamBrowser.Contracts/UserInterface/IUserInterfaceFactory.cs +++ b/SafeExamBrowser.Contracts/UserInterface/IUserInterfaceFactory.cs @@ -68,7 +68,7 @@ namespace SafeExamBrowser.Contracts.UserInterface /// /// Creates a system control displaying the power supply status of the computer. /// - ISystemPowerSupplyControl CreatePowerSupplyControl(); + ISystemPowerSupplyControl CreatePowerSupplyControl(Location location); /// /// Creates a new runtime window which runs on its own thread. diff --git a/SafeExamBrowser.Contracts/UserInterface/Shell/ISystemControl.cs b/SafeExamBrowser.Contracts/UserInterface/Shell/ISystemControl.cs index b47f5f1a..dcea5b6d 100644 --- a/SafeExamBrowser.Contracts/UserInterface/Shell/ISystemControl.cs +++ b/SafeExamBrowser.Contracts/UserInterface/Shell/ISystemControl.cs @@ -19,8 +19,8 @@ namespace SafeExamBrowser.Contracts.UserInterface.Shell void Close(); /// - /// Sets the tooltip text of the system control. + /// Sets the information text of the system control. /// - void SetTooltip(string text); + void SetInformation(string text); } } diff --git a/SafeExamBrowser.I18n/Text.xml b/SafeExamBrowser.I18n/Text.xml index 254a8b10..d68c6292 100644 --- a/SafeExamBrowser.I18n/Text.xml +++ b/SafeExamBrowser.I18n/Text.xml @@ -34,7 +34,7 @@ Download Error - The configuration resource '%%URI%%' contains invalid data! + The configuration resource "%%URI%%" contains invalid data! Configuration Error @@ -52,7 +52,7 @@ Invalid Quit Password - The configuration resource '%%URI%%' is not supported! + The configuration resource "%%URI%%" is not supported! Configuration Error @@ -106,7 +106,7 @@ Startup Error - An unexpected error occurred while trying to load configuration resource '%%URI%%'! Please consult the application log for more information... + An unexpected error occurred while trying to load configuration resource "%%URI%%"! Please consult the application log for more information... Configuration Error @@ -262,10 +262,10 @@ %%HOURS%%h %%MINUTES%%min remaining (%%CHARGE%%%) - Click to choose a different keyboard layout... + The current keyboard layout is "%%LAYOUT%%" - Connected to '%%NAME%%' + Connected to "%%NAME%%" Disconnected diff --git a/SafeExamBrowser.SystemComponents/KeyboardLayout.cs b/SafeExamBrowser.SystemComponents/KeyboardLayout.cs index f76ec5f8..e7b96667 100644 --- a/SafeExamBrowser.SystemComponents/KeyboardLayout.cs +++ b/SafeExamBrowser.SystemComponents/KeyboardLayout.cs @@ -72,7 +72,7 @@ namespace SafeExamBrowser.SystemComponents control.LayoutSelected += Control_LayoutSelected; control.SetCurrent(currentLayout); - control.SetTooltip(text.Get(TextKey.SystemControl_KeyboardLayoutTooltip)); + control.SetInformation(GetInfoTextFor(currentLayout)); controls.Add(control); } @@ -97,8 +97,8 @@ namespace SafeExamBrowser.SystemComponents { var layout = layouts.First(l => l.Id == id); + logger.Info($"Changing keyboard layout to {ToString(layout.CultureInfo)}."); InputLanguageManager.Current.CurrentInputLanguage = layout.CultureInfo; - logger.Info($"Changed keyboard layout to {ToString(layout.CultureInfo)}."); } private void Current_InputLanguageChanged(object sender, InputLanguageEventArgs e) @@ -111,9 +111,15 @@ namespace SafeExamBrowser.SystemComponents foreach (var control in controls) { control.SetCurrent(newLayout); + control.SetInformation(GetInfoTextFor(newLayout)); } } + private string GetInfoTextFor(KeyboardLayoutDefinition layout) + { + return text.Get(TextKey.SystemControl_KeyboardLayoutTooltip).Replace("%%LAYOUT%%", layout.CultureInfo.NativeName); + } + private string ToString(CultureInfo info) { return $"'{info.DisplayName}' ({info.ThreeLetterISOLanguageName.ToUpper()})"; diff --git a/SafeExamBrowser.SystemComponents/PowerSupply.cs b/SafeExamBrowser.SystemComponents/PowerSupply.cs index 5990f205..f8804e92 100644 --- a/SafeExamBrowser.SystemComponents/PowerSupply.cs +++ b/SafeExamBrowser.SystemComponents/PowerSupply.cs @@ -78,46 +78,54 @@ namespace SafeExamBrowser.SystemComponents var online = SystemInformation.PowerStatus.PowerLineStatus == PowerLineStatus.Online; var tooltip = string.Empty; + 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(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()); + foreach (var control in controls) { - 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); + control.SetInformation(tooltip); } } - private void HandleBatteryStatus(ISystemPowerSupplyControl control, BatteryChargeStatus status) + private void HandleBatteryStatus(BatteryChargeStatus status) { if (status == BatteryChargeStatus.Low && !infoShown) { - control.ShowLowBatteryInfo(text.Get(TextKey.SystemControl_BatteryChargeLowInfo)); + foreach (var control in controls) + { + control.ShowLowBatteryInfo(text.Get(TextKey.SystemControl_BatteryChargeLowInfo)); + } + infoShown = true; logger.Info("Informed the user about low battery charge."); } if (status == BatteryChargeStatus.Critical && !warningShown) { - control.ShowCriticalBatteryWarning(text.Get(TextKey.SystemControl_BatteryChargeCriticalWarning)); + foreach (var control in controls) + { + control.ShowCriticalBatteryWarning(text.Get(TextKey.SystemControl_BatteryChargeCriticalWarning)); + } + warningShown = true; logger.Warn("Warned the user about critical battery charge."); } diff --git a/SafeExamBrowser.SystemComponents/WirelessNetwork.cs b/SafeExamBrowser.SystemComponents/WirelessNetwork.cs index 58694d9d..b318bd29 100644 --- a/SafeExamBrowser.SystemComponents/WirelessNetwork.cs +++ b/SafeExamBrowser.SystemComponents/WirelessNetwork.cs @@ -72,7 +72,7 @@ namespace SafeExamBrowser.SystemComponents else { control.HasWirelessNetworkAdapter = false; - control.SetTooltip(text.Get(TextKey.SystemControl_WirelessNotAvailable)); + control.SetInformation(text.Get(TextKey.SystemControl_WirelessNotAvailable)); } controls.Add(control); @@ -198,12 +198,12 @@ namespace SafeExamBrowser.SystemComponents { if (wifi.ConnectionStatus == WifiStatus.Disconnected) { - control.SetTooltip(text.Get(TextKey.SystemControl_WirelessDisconnected)); + control.SetInformation(text.Get(TextKey.SystemControl_WirelessDisconnected)); } if (isConnected) { - control.SetTooltip(text.Get(TextKey.SystemControl_WirelessConnected).Replace("%%NAME%%", networkName)); + control.SetInformation(text.Get(TextKey.SystemControl_WirelessConnected).Replace("%%NAME%%", networkName)); } control.NetworkStatus = ToStatus(wifi.ConnectionStatus); diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterKeyboardLayoutControl.xaml b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterKeyboardLayoutControl.xaml index 9b89d427..2a05366e 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterKeyboardLayoutControl.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterKeyboardLayoutControl.xaml @@ -15,9 +15,9 @@ - - - + + + diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterKeyboardLayoutControl.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterKeyboardLayoutControl.xaml.cs index 30f8f1ad..3330708f 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterKeyboardLayoutControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterKeyboardLayoutControl.xaml.cs @@ -9,6 +9,7 @@ using System; using System.Threading.Tasks; using System.Windows.Controls; +using System.Windows.Media; using SafeExamBrowser.Contracts.SystemComponents; using SafeExamBrowser.Contracts.UserInterface.Shell; using SafeExamBrowser.Contracts.UserInterface.Shell.Events; @@ -60,16 +61,20 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls }); } - public void SetTooltip(string text) + public void SetInformation(string text) { Dispatcher.Invoke(() => Button.ToolTip = text); } private void InitializeKeyboardLayoutControl() { + var originalBrush = Grid.Background; + Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen; Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver)); Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver)); + Popup.Opened += (o, args) => Grid.Background = Brushes.Gray; + Popup.Closed += (o, args) => Grid.Background = originalBrush; } private void Button_LayoutSelected(Guid id) diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterPowerSupplyControl.xaml b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterPowerSupplyControl.xaml new file mode 100644 index 00000000..62571393 --- /dev/null +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterPowerSupplyControl.xaml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterPowerSupplyControl.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterPowerSupplyControl.xaml.cs new file mode 100644 index 00000000..ee843c85 --- /dev/null +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterPowerSupplyControl.xaml.cs @@ -0,0 +1,67 @@ +/* + * 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 System.Windows.Media; +using SafeExamBrowser.Contracts.SystemComponents; +using SafeExamBrowser.Contracts.UserInterface.Shell; + +namespace SafeExamBrowser.UserInterface.Desktop.Controls +{ + public partial class ActionCenterPowerSupplyControl : UserControl, ISystemPowerSupplyControl + { + private double BATTERY_CHARGE_MAX_WIDTH; + + public ActionCenterPowerSupplyControl() + { + InitializeComponent(); + BATTERY_CHARGE_MAX_WIDTH = BatteryCharge.Width; + } + + public void Close() + { + } + + public void SetBatteryCharge(double charge, BatteryChargeStatus status) + { + Dispatcher.InvokeAsync(() => + { + var width = BATTERY_CHARGE_MAX_WIDTH * charge; + + width = width > BATTERY_CHARGE_MAX_WIDTH ? BATTERY_CHARGE_MAX_WIDTH : width; + width = width < 0 ? 0 : width; + + BatteryCharge.Width = width; + BatteryCharge.Fill = status == BatteryChargeStatus.Low ? Brushes.Orange : BatteryCharge.Fill; + BatteryCharge.Fill = status == BatteryChargeStatus.Critical ? Brushes.Red : BatteryCharge.Fill; + Warning.Visibility = status == BatteryChargeStatus.Critical ? Visibility.Visible : Visibility.Collapsed; + }); + } + + public void SetPowerGridConnection(bool connected) + { + Dispatcher.InvokeAsync(() => PowerPlug.Visibility = connected ? Visibility.Visible : Visibility.Collapsed); + } + + public void SetInformation(string text) + { + Dispatcher.InvokeAsync(() => Text.Text = text); + } + + public void ShowCriticalBatteryWarning(string warning) + { + Dispatcher.InvokeAsync(() => Button.ToolTip = warning); + } + + public void ShowLowBatteryInfo(string info) + { + Dispatcher.InvokeAsync(() => Button.ToolTip = info); + } + } +} diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarKeyboardLayoutControl.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarKeyboardLayoutControl.xaml.cs index 9bace59a..7ea69055 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarKeyboardLayoutControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarKeyboardLayoutControl.xaml.cs @@ -64,7 +64,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls }); } - public void SetTooltip(string text) + public void SetInformation(string text) { Dispatcher.Invoke(() => Button.ToolTip = text); } diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/PowerSupplyControl.xaml b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarPowerSupplyControl.xaml similarity index 99% rename from SafeExamBrowser.UserInterface.Desktop/Controls/PowerSupplyControl.xaml rename to SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarPowerSupplyControl.xaml index c9e4360d..538ce678 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/PowerSupplyControl.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskbarPowerSupplyControl.xaml @@ -1,4 +1,4 @@ - PowerPlug.Visibility = connected ? Visibility.Visible : Visibility.Collapsed); } - public void SetTooltip(string text) + public void SetInformation(string text) { Dispatcher.InvokeAsync(() => Button.ToolTip = text); } @@ -71,14 +71,12 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls Popup.IsOpen = true; PopupText.Text = text; Background = Brushes.LightGray; - Button.IsEnabled = true; } private void Button_Click(object sender, RoutedEventArgs e) { Popup.IsOpen = false; Background = Brushes.Transparent; - Button.IsEnabled = false; } } } diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/WirelessNetworkControl.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/WirelessNetworkControl.xaml.cs index 6dce0dc2..1c2460d6 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/WirelessNetworkControl.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/WirelessNetworkControl.xaml.cs @@ -74,7 +74,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls Popup.IsOpen = false; } - public void SetTooltip(string text) + public void SetInformation(string text) { Dispatcher.InvokeAsync(() => Button.ToolTip = text); } diff --git a/SafeExamBrowser.UserInterface.Desktop/SafeExamBrowser.UserInterface.Desktop.csproj b/SafeExamBrowser.UserInterface.Desktop/SafeExamBrowser.UserInterface.Desktop.csproj index 69efc3e2..9f46a5f8 100644 --- a/SafeExamBrowser.UserInterface.Desktop/SafeExamBrowser.UserInterface.Desktop.csproj +++ b/SafeExamBrowser.UserInterface.Desktop/SafeExamBrowser.UserInterface.Desktop.csproj @@ -89,6 +89,9 @@ ActionCenterNotificationButton.xaml + + ActionCenterPowerSupplyControl.xaml + TaskbarApplicationControl.xaml @@ -107,8 +110,8 @@ TaskbarNotificationButton.xaml - - PowerSupplyControl.xaml + + TaskbarPowerSupplyControl.xaml QuitButton.xaml @@ -172,6 +175,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile @@ -196,7 +203,7 @@ Designer MSBuild:Compile - + MSBuild:Compile Designer diff --git a/SafeExamBrowser.UserInterface.Desktop/Templates/Colors.xaml b/SafeExamBrowser.UserInterface.Desktop/Templates/Colors.xaml index 53b030d0..468c0504 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Templates/Colors.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/Templates/Colors.xaml @@ -1,6 +1,5 @@  + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> #FFF0F0F0 #AA808080 \ No newline at end of file diff --git a/SafeExamBrowser.UserInterface.Desktop/Templates/ScrollViewers.xaml b/SafeExamBrowser.UserInterface.Desktop/Templates/ScrollViewers.xaml index 1f7d7402..62595500 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Templates/ScrollViewers.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/Templates/ScrollViewers.xaml @@ -1,6 +1,5 @@  + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> diff --git a/SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs b/SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs index 0ac39827..41d059ea 100644 --- a/SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs +++ b/SafeExamBrowser.UserInterface.Desktop/UserInterfaceFactory.cs @@ -115,9 +115,16 @@ namespace SafeExamBrowser.UserInterface.Desktop return Application.Current.Dispatcher.Invoke(() => new PasswordDialog(text.Get(message), text.Get(title), text)); } - public ISystemPowerSupplyControl CreatePowerSupplyControl() + public ISystemPowerSupplyControl CreatePowerSupplyControl(Location location) { - return new PowerSupplyControl(); + if (location == Location.ActionCenter) + { + return new ActionCenterPowerSupplyControl(); + } + else + { + return new TaskbarPowerSupplyControl(); + } } public IRuntimeWindow CreateRuntimeWindow(AppConfig appConfig)