SEBWIN-141: Implemented quit button and clock for action center.

This commit is contained in:
dbuechel 2019-03-15 11:38:59 +01:00
parent a47f68422c
commit b4ae1745fc
25 changed files with 331 additions and 102 deletions

View file

@ -12,6 +12,7 @@ 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;
@ -25,18 +26,19 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
private Mock<IActionCenter> actionCenter;
private Mock<IEnumerable<IActionCenterActivator>> activators;
private ActionCenterSettings actionCenterSettings;
private Mock<ILogger> loggerMock;
private Mock<ILogger> logger;
private TaskbarSettings taskbarSettings;
private Mock<INotificationInfo> aboutInfoMock;
private Mock<INotificationController> aboutControllerMock;
private Mock<INotificationInfo> logInfoMock;
private Mock<INotificationController> logControllerMock;
private Mock<ISystemComponent<ISystemKeyboardLayoutControl>> keyboardLayoutMock;
private Mock<ISystemComponent<ISystemPowerSupplyControl>> powerSupplyMock;
private Mock<ISystemComponent<ISystemWirelessNetworkControl>> wirelessNetworkMock;
private Mock<ISystemInfo> systemInfoMock;
private Mock<ITaskbar> taskbarMock;
private Mock<IUserInterfaceFactory> uiFactoryMock;
private Mock<INotificationInfo> aboutInfo;
private Mock<INotificationController> aboutController;
private Mock<INotificationInfo> logInfo;
private Mock<INotificationController> logController;
private Mock<ISystemComponent<ISystemKeyboardLayoutControl>> keyboardLayout;
private Mock<ISystemComponent<ISystemPowerSupplyControl>> powerSupply;
private Mock<ISystemComponent<ISystemWirelessNetworkControl>> wirelessNetwork;
private Mock<ISystemInfo> systemInfo;
private Mock<ITaskbar> taskbar;
private Mock<IText> text;
private Mock<IUserInterfaceFactory> uiFactory;
private ShellOperation sut;
@ -46,42 +48,44 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
actionCenter = new Mock<IActionCenter>();
activators = new Mock<IEnumerable<IActionCenterActivator>>();
actionCenterSettings = new ActionCenterSettings();
loggerMock = new Mock<ILogger>();
aboutInfoMock = new Mock<INotificationInfo>();
aboutControllerMock = new Mock<INotificationController>();
logInfoMock = new Mock<INotificationInfo>();
logControllerMock = new Mock<INotificationController>();
keyboardLayoutMock = new Mock<ISystemComponent<ISystemKeyboardLayoutControl>>();
powerSupplyMock = new Mock<ISystemComponent<ISystemPowerSupplyControl>>();
wirelessNetworkMock = new Mock<ISystemComponent<ISystemWirelessNetworkControl>>();
systemInfoMock = new Mock<ISystemInfo>();
taskbarMock = new Mock<ITaskbar>();
logger = new Mock<ILogger>();
aboutInfo = new Mock<INotificationInfo>();
aboutController = new Mock<INotificationController>();
logInfo = new Mock<INotificationInfo>();
logController = new Mock<INotificationController>();
keyboardLayout = new Mock<ISystemComponent<ISystemKeyboardLayoutControl>>();
powerSupply = new Mock<ISystemComponent<ISystemPowerSupplyControl>>();
wirelessNetwork = new Mock<ISystemComponent<ISystemWirelessNetworkControl>>();
systemInfo = new Mock<ISystemInfo>();
taskbar = new Mock<ITaskbar>();
taskbarSettings = new TaskbarSettings();
uiFactoryMock = new Mock<IUserInterfaceFactory>();
text = new Mock<IText>();
uiFactory = new Mock<IUserInterfaceFactory>();
taskbarSettings.ShowApplicationLog = true;
taskbarSettings.ShowKeyboardLayout = true;
taskbarSettings.ShowWirelessNetwork = true;
taskbarSettings.EnableTaskbar = true;
systemInfoMock.SetupGet(s => s.HasBattery).Returns(true);
uiFactoryMock.Setup(u => u.CreateNotificationControl(It.IsAny<INotificationInfo>(), It.IsAny<Location>())).Returns(new Mock<INotificationControl>().Object);
systemInfo.SetupGet(s => s.HasBattery).Returns(true);
uiFactory.Setup(u => u.CreateNotificationControl(It.IsAny<INotificationInfo>(), It.IsAny<Location>())).Returns(new Mock<INotificationControl>().Object);
sut = new ShellOperation(
actionCenter.Object,
activators.Object,
actionCenterSettings,
loggerMock.Object,
aboutInfoMock.Object,
aboutControllerMock.Object,
logInfoMock.Object,
logControllerMock.Object,
keyboardLayoutMock.Object,
powerSupplyMock.Object,
wirelessNetworkMock.Object,
systemInfoMock.Object,
taskbarMock.Object,
logger.Object,
aboutInfo.Object,
aboutController.Object,
logInfo.Object,
logController.Object,
keyboardLayout.Object,
powerSupply.Object,
wirelessNetwork.Object,
systemInfo.Object,
taskbar.Object,
taskbarSettings,
uiFactoryMock.Object);
text.Object,
uiFactory.Object);
}
[TestMethod]
@ -89,11 +93,11 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
{
sut.Perform();
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<ISystemControl>()), Times.Exactly(3));
taskbarMock.Verify(t => t.AddNotificationControl(It.IsAny<INotificationControl>()), Times.Exactly(2));
keyboardLayout.Verify(k => k.Initialize(), Times.Once);
powerSupply.Verify(p => p.Initialize(), Times.Once);
wirelessNetwork.Verify(w => w.Initialize(), Times.Once);
taskbar.Verify(t => t.AddSystemControl(It.IsAny<ISystemControl>()), Times.Exactly(3));
taskbar.Verify(t => t.AddNotificationControl(It.IsAny<INotificationControl>()), Times.Exactly(2));
}
[TestMethod]
@ -101,10 +105,10 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
{
sut.Revert();
aboutControllerMock.Verify(c => c.Terminate(), Times.Once);
keyboardLayoutMock.Verify(k => k.Terminate(), Times.Once);
powerSupplyMock.Verify(p => p.Terminate(), Times.Once);
wirelessNetworkMock.Verify(w => w.Terminate(), Times.Once);
aboutController.Verify(c => c.Terminate(), Times.Once);
keyboardLayout.Verify(k => k.Terminate(), Times.Once);
powerSupply.Verify(p => p.Terminate(), Times.Once);
wirelessNetwork.Verify(w => w.Terminate(), Times.Once);
}
}
}

View file

@ -168,6 +168,7 @@ namespace SafeExamBrowser.Client
private void RegisterEvents()
{
actionCenter.QuitButtonClicked += Shell_QuitButtonClicked;
Browser.ConfigurationDownloadRequested += Browser_ConfigurationDownloadRequested;
ClientHost.MessageBoxRequested += ClientHost_MessageBoxRequested;
ClientHost.PasswordRequested += ClientHost_PasswordRequested;
@ -176,16 +177,17 @@ namespace SafeExamBrowser.Client
displayMonitor.DisplayChanged += DisplayMonitor_DisplaySettingsChanged;
processMonitor.ExplorerStarted += ProcessMonitor_ExplorerStarted;
runtime.ConnectionLost += Runtime_ConnectionLost;
taskbar.QuitButtonClicked += Taskbar_QuitButtonClicked;
taskbar.QuitButtonClicked += Shell_QuitButtonClicked;
windowMonitor.WindowChanged += WindowMonitor_WindowChanged;
}
private void DeregisterEvents()
{
actionCenter.QuitButtonClicked -= Shell_QuitButtonClicked;
displayMonitor.DisplayChanged -= DisplayMonitor_DisplaySettingsChanged;
processMonitor.ExplorerStarted -= ProcessMonitor_ExplorerStarted;
runtime.ConnectionLost -= Runtime_ConnectionLost;
taskbar.QuitButtonClicked -= Taskbar_QuitButtonClicked;
taskbar.QuitButtonClicked -= Shell_QuitButtonClicked;
windowMonitor.WindowChanged -= WindowMonitor_WindowChanged;
if (Browser != null)
@ -216,26 +218,6 @@ namespace SafeExamBrowser.Client
Browser.Start();
}
private void DisplayMonitor_DisplaySettingsChanged()
{
logger.Info("Reinitializing working area...");
displayMonitor.InitializePrimaryDisplay(taskbar.GetAbsoluteHeight());
logger.Info("Reinitializing taskbar bounds...");
taskbar.InitializeBounds();
logger.Info("Desktop successfully restored.");
}
private void ProcessMonitor_ExplorerStarted()
{
logger.Info("Trying to terminate Windows explorer...");
explorerShell.Terminate();
logger.Info("Reinitializing working area...");
displayMonitor.InitializePrimaryDisplay(taskbar.GetAbsoluteHeight());
logger.Info("Reinitializing taskbar bounds...");
taskbar.InitializeBounds();
logger.Info("Desktop successfully restored.");
}
private void Browser_ConfigurationDownloadRequested(string fileName, DownloadEventArgs args)
{
if (Settings.ConfigurationMode == ConfigurationMode.ConfigureClient)
@ -337,6 +319,15 @@ namespace SafeExamBrowser.Client
shutdown.Invoke();
}
private void DisplayMonitor_DisplaySettingsChanged()
{
logger.Info("Reinitializing working area...");
displayMonitor.InitializePrimaryDisplay(taskbar.GetAbsoluteHeight());
logger.Info("Reinitializing taskbar bounds...");
taskbar.InitializeBounds();
logger.Info("Desktop successfully restored.");
}
private void Operations_ProgressChanged(ProgressChangedEventArgs args)
{
if (args.CurrentValue.HasValue)
@ -370,6 +361,17 @@ namespace SafeExamBrowser.Client
splashScreen?.UpdateStatus(status, true);
}
private void ProcessMonitor_ExplorerStarted()
{
logger.Info("Trying to terminate Windows explorer...");
explorerShell.Terminate();
logger.Info("Reinitializing working area...");
displayMonitor.InitializePrimaryDisplay(taskbar.GetAbsoluteHeight());
logger.Info("Reinitializing taskbar bounds...");
taskbar.InitializeBounds();
logger.Info("Desktop successfully restored.");
}
private void Runtime_ConnectionLost()
{
logger.Error("Lost connection to the runtime!");
@ -378,7 +380,7 @@ namespace SafeExamBrowser.Client
shutdown.Invoke();
}
private void Taskbar_QuitButtonClicked(System.ComponentModel.CancelEventArgs args)
private void Shell_QuitButtonClicked(System.ComponentModel.CancelEventArgs args)
{
var hasQuitPassword = !String.IsNullOrEmpty(Settings.QuitPasswordHash);
var requestShutdown = false;

View file

@ -94,7 +94,7 @@ namespace SafeExamBrowser.Client
processMonitor = new ProcessMonitor(new ModuleLogger(logger, nameof(ProcessMonitor)), nativeMethods);
uiFactory = new UserInterfaceFactory(text);
runtimeProxy = new RuntimeProxy(runtimeHostUri, new ProxyObjectFactory(), new ModuleLogger(logger, nameof(RuntimeProxy)));
taskbar = new Taskbar(new ModuleLogger(logger, nameof(taskbar)));
taskbar = new Taskbar(new ModuleLogger(logger, nameof(Taskbar)));
windowMonitor = new WindowMonitor(new ModuleLogger(logger, nameof(WindowMonitor)), nativeMethods);
wirelessNetwork = new WirelessNetwork(new ModuleLogger(logger, nameof(WirelessNetwork)), text);
@ -276,6 +276,7 @@ namespace SafeExamBrowser.Client
systemInfo,
taskbar,
configuration.Settings.Taskbar,
text,
uiFactory);
return operation;

View file

@ -35,6 +35,7 @@ namespace SafeExamBrowser.Client.Operations
private ISystemInfo systemInfo;
private ITaskbar taskbar;
private TaskbarSettings taskbarSettings;
private IText text;
private IUserInterfaceFactory uiFactory;
public event ActionRequiredEventHandler ActionRequired { add { } remove { } }
@ -55,6 +56,7 @@ namespace SafeExamBrowser.Client.Operations
ISystemInfo systemInfo,
ITaskbar taskbar,
TaskbarSettings taskbarSettings,
IText text,
IUserInterfaceFactory uiFactory)
{
this.aboutInfo = aboutInfo;
@ -67,8 +69,9 @@ namespace SafeExamBrowser.Client.Operations
this.logController = logController;
this.keyboardLayout = keyboardLayout;
this.powerSupply = powerSupply;
this.taskbarSettings = taskbarSettings;
this.systemInfo = systemInfo;
this.taskbarSettings = taskbarSettings;
this.text = text;
this.taskbar = taskbar;
this.uiFactory = uiFactory;
this.wirelessNetwork = wirelessNetwork;
@ -102,6 +105,7 @@ namespace SafeExamBrowser.Client.Operations
if (actionCenterSettings.EnableActionCenter)
{
logger.Info("Initializing action center...");
actionCenter.InitializeText(text);
InitializeAboutNotificationForActionCenter();
InitializeClockForActionCenter();
@ -127,6 +131,7 @@ namespace SafeExamBrowser.Client.Operations
if (taskbarSettings.EnableTaskbar)
{
logger.Info("Initializing taskbar...");
taskbar.InitializeText(text);
InitializeAboutNotificationForTaskbar();
InitializeClockForTaskbar();
@ -166,7 +171,7 @@ namespace SafeExamBrowser.Client.Operations
private void InitializeClockForActionCenter()
{
//TODO: actionCenter.ShowClock = settings.ShowClock;
actionCenter.ShowClock = actionCenterSettings.ShowClock;
}
private void InitializeClockForTaskbar()

View file

@ -89,6 +89,10 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
var settings = new Settings();
settings.ActionCenter.EnableActionCenter = true;
settings.ActionCenter.ShowApplicationLog = false;
settings.ActionCenter.ShowKeyboardLayout = true;
settings.ActionCenter.ShowWirelessNetwork = false;
settings.ActionCenter.ShowClock = true;
settings.Browser.StartUrl = "https://www.safeexambrowser.org/start";
settings.Browser.AllowConfigurationDownloads = true;

View file

@ -25,6 +25,11 @@ namespace SafeExamBrowser.Contracts.Configuration.Settings
/// Determines whether the application log is accessible via the action center.
/// </summary>
public bool ShowApplicationLog { get; set; }
/// <summary>
/// Determines whether the current date and time will be rendered in the action center.
/// </summary>
public bool ShowClock { get; set; }
/// <summary>
/// Determines whether the system control for the keyboard layout is accessible via the action center.

View file

@ -96,6 +96,7 @@ namespace SafeExamBrowser.Contracts.I18n
PasswordDialog_SettingsPasswordRequired,
PasswordDialog_SettingsPasswordRequiredTitle,
RuntimeWindow_ApplicationRunning,
Shell_QuitButton,
SystemControl_BatteryCharged,
SystemControl_BatteryCharging,
SystemControl_BatteryChargeCriticalWarning,

View file

@ -6,6 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.UserInterface.Shell.Events;
namespace SafeExamBrowser.Contracts.UserInterface.Shell
@ -15,6 +16,11 @@ namespace SafeExamBrowser.Contracts.UserInterface.Shell
/// </summary>
public interface IActionCenter
{
/// <summary>
/// Controls the visibility of the clock.
/// </summary>
bool ShowClock { set; }
/// <summary>
/// Event fired when the user clicked the quit button.
/// </summary>
@ -44,6 +50,11 @@ namespace SafeExamBrowser.Contracts.UserInterface.Shell
/// Makes the action center invisible.
/// </summary>
void Hide();
/// <summary>
/// Initializes all text elements in the action center.
/// </summary>
void InitializeText(IText text);
/// <summary>
/// Registers the specified activator to control the visibility of the action center.

View file

@ -6,6 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.UserInterface.Shell.Events;
namespace SafeExamBrowser.Contracts.UserInterface.Shell
@ -55,6 +56,11 @@ namespace SafeExamBrowser.Contracts.UserInterface.Shell
/// </summary>
void InitializeBounds();
/// <summary>
/// Initializes all text elements in the taskbar.
/// </summary>
void InitializeText(IText text);
/// <summary>
/// Shows the taskbar.
/// </summary>

View file

@ -112,7 +112,7 @@
Configuration Error
</Entry>
<Entry key="Notification_AboutTooltip">
About Safe Exam Browser
Information about SEB
</Entry>
<Entry key="Notification_LogTooltip">
Application Log
@ -246,6 +246,9 @@
<Entry key="RuntimeWindow_ApplicationRunning">
The application is running.
</Entry>
<Entry key="Shell_QuitButton">
Terminate Session
</Entry>
<Entry key="SystemControl_BatteryCharging">
Plugged in, charging... (%%CHARGE%%%)
</Entry>

View file

@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
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"
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls"
mc:Ignorable="d" Title="ActionCenter" Height="1000" Width="400" Background="#EEF0F0F0" AllowsTransparency="True" WindowStyle="None" Topmost="True" ResizeMode="NoResize">
<Window.Resources>
<ResourceDictionary>
@ -20,6 +20,9 @@
<ScrollViewer Grid.Row="0" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto" Template="{StaticResource SmallBarScrollViewer}">
<StackPanel x:Name="ApplicationPanel" Orientation="Vertical" />
</ScrollViewer>
<UniformGrid x:Name="ControlPanel" Grid.Row="1" Columns="4" Margin="10" />
<UniformGrid x:Name="ControlPanel" Grid.Row="1" Columns="4" Margin="10">
<local:ActionCenterClock x:Name="Clock" />
<local:ActionCenterQuitButton x:Name="QuitButton" />
</UniformGrid>
</Grid>
</Window>

View file

@ -9,6 +9,7 @@
using System;
using System.Windows;
using System.Windows.Media.Animation;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.UserInterface.Shell;
using SafeExamBrowser.Contracts.UserInterface.Shell.Events;
@ -16,11 +17,17 @@ namespace SafeExamBrowser.UserInterface.Desktop
{
public partial class ActionCenter : Window, IActionCenter
{
public bool ShowClock
{
set { Dispatcher.Invoke(() => Clock.Visibility = value ? Visibility.Visible : Visibility.Collapsed); }
}
public event QuitButtonClickedEventHandler QuitButtonClicked;
public ActionCenter()
{
InitializeComponent();
InitializeActionCenter();
}
public void AddApplicationControl(IApplicationControl control)
@ -35,7 +42,7 @@ namespace SafeExamBrowser.UserInterface.Desktop
{
if (control is UIElement uiElement)
{
ControlPanel.Children.Add(uiElement);
ControlPanel.Children.Insert(ControlPanel.Children.Count - 2, uiElement);
}
}
@ -43,7 +50,7 @@ namespace SafeExamBrowser.UserInterface.Desktop
{
if (control is UIElement uiElement)
{
ControlPanel.Children.Add(uiElement);
ControlPanel.Children.Insert(ControlPanel.Children.Count - 2, uiElement);
}
}
@ -57,6 +64,12 @@ namespace SafeExamBrowser.UserInterface.Desktop
Dispatcher.Invoke(HideAnimated);
}
public void InitializeText(IText text)
{
QuitButton.ToolTip = text.Get(TextKey.Shell_QuitButton);
QuitButton.Text.Text = text.Get(TextKey.Shell_QuitButton);
}
public void Register(IActionCenterActivator activator)
{
activator.Activate += Activator_Activate;
@ -170,5 +183,10 @@ namespace SafeExamBrowser.UserInterface.Desktop
}
});
}
private void InitializeActionCenter()
{
QuitButton.Clicked += (args) => QuitButtonClicked?.Invoke(args);
}
}
}

View file

@ -0,0 +1,36 @@
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenterClock"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:fa="http://schemas.fontawesome.io/icons/"
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls"
mc:Ignorable="d" d:DesignHeight="100" d:DesignWidth="125">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Templates/Buttons.xaml" />
<ResourceDictionary Source="../Templates/Colors.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid Background="{StaticResource ActionCenterDarkBrush}" Height="64" Margin="2" ToolTip="{Binding Path=ToolTip}">
<Button x:Name="Button" IsEnabled="False" Padding="2" Template="{StaticResource ActionCenterButton}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*" />
<RowDefinition Height="3*" />
</Grid.RowDefinitions>
<fa:ImageAwesome Grid.Row="0" Foreground="Black" Icon="ClockOutline" Margin="2" VerticalAlignment="Center" />
<Grid Grid.Row="1" Background="Transparent" Margin="5,0" VerticalAlignment="Bottom">
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<TextBlock x:Name="TimeTextBlock" Grid.Row="0" Text="{Binding Path=Time}" FontSize="11" Foreground="White" HorizontalAlignment="Center" />
<TextBlock x:Name="DateTextBlock" Grid.Row="1" Text="{Binding Path=Date}" FontSize="11" Foreground="White" HorizontalAlignment="Center" />
</Grid>
</Grid>
</Button>
</Grid>
</UserControl>

View file

@ -0,0 +1,32 @@
/*
* 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.Controls;
using SafeExamBrowser.UserInterface.Desktop.ViewModels;
namespace SafeExamBrowser.UserInterface.Desktop.Controls
{
public partial class ActionCenterClock : UserControl
{
private DateTimeViewModel model;
public ActionCenterClock()
{
InitializeComponent();
InitializeControl();
}
private void InitializeControl()
{
model = new DateTimeViewModel(true);
DataContext = model;
TimeTextBlock.DataContext = model;
DateTextBlock.DataContext = model;
}
}
}

View file

@ -20,7 +20,7 @@
<RowDefinition Height="2*" />
<RowDefinition Height="3*" />
</Grid.RowDefinitions>
<ContentControl Grid.Row="0" x:Name="Icon" Foreground="White" VerticalAlignment="Center" />
<ContentControl Grid.Row="0" x:Name="Icon" VerticalAlignment="Center" />
<TextBlock Grid.Row="1" x:Name="Text" FontSize="11" Foreground="White" TextAlignment="Center" TextTrimming="CharacterEllipsis" TextWrapping="Wrap" VerticalAlignment="Bottom" />
</Grid>
</Button>

View file

@ -0,0 +1,28 @@
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.ActionCenterQuitButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls"
mc:Ignorable="d" d:DesignHeight="100" d:DesignWidth="125">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Templates/Buttons.xaml" />
<ResourceDictionary Source="../Templates/Colors.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid Background="{StaticResource ActionCenterDarkBrush}" Height="64" Margin="2">
<Button x:Name="Button" Padding="2" Template="{StaticResource ActionCenterButton}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*" />
<RowDefinition Height="3*" />
</Grid.RowDefinitions>
<ContentControl Grid.Row="0" x:Name="Icon" Foreground="Black" VerticalAlignment="Center" />
<TextBlock Grid.Row="1" x:Name="Text" FontSize="11" Foreground="White" TextAlignment="Center" TextTrimming="CharacterEllipsis" TextWrapping="Wrap" VerticalAlignment="Bottom" />
</Grid>
</Button>
</Grid>
</UserControl>

View file

@ -0,0 +1,36 @@
/*
* 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;
using System.ComponentModel;
using System.Windows.Controls;
using SafeExamBrowser.Contracts.UserInterface.Shell.Events;
using SafeExamBrowser.UserInterface.Desktop.Utilities;
namespace SafeExamBrowser.UserInterface.Desktop.Controls
{
public partial class ActionCenterQuitButton : UserControl
{
public event QuitButtonClickedEventHandler Clicked;
public ActionCenterQuitButton()
{
InitializeComponent();
InitializeControl();
}
private void InitializeControl()
{
var uri = new Uri("pack://application:,,,/SafeExamBrowser.UserInterface.Desktop;component/Images/ShutDown.xaml");
var resource = new XamlIconResource(uri);
Icon.Content = IconResourceLoader.Load(resource);
Button.Click += (o, args) => Clicked?.Invoke(new CancelEventArgs());
}
}
}

View file

@ -1,4 +1,4 @@
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.DateTimeControl"
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.TaskbarClock"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

View file

@ -11,14 +11,19 @@ using SafeExamBrowser.UserInterface.Desktop.ViewModels;
namespace SafeExamBrowser.UserInterface.Desktop.Controls
{
public partial class DateTimeControl : UserControl
public partial class TaskbarClock : UserControl
{
private DateTimeViewModel model = new DateTimeViewModel();
private DateTimeViewModel model;
public DateTimeControl()
public TaskbarClock()
{
InitializeComponent();
InitializeControl();
}
private void InitializeControl()
{
model = new DateTimeViewModel(false);
DataContext = model;
TimeTextBlock.DataContext = model;
DateTextBlock.DataContext = model;

View file

@ -1,4 +1,4 @@
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.QuitButton"
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.TaskbarQuitButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

View file

@ -15,11 +15,11 @@ using SafeExamBrowser.UserInterface.Desktop.Utilities;
namespace SafeExamBrowser.UserInterface.Desktop.Controls
{
public partial class QuitButton : UserControl
public partial class TaskbarQuitButton : UserControl
{
public event QuitButtonClickedEventHandler Clicked;
public QuitButton()
public TaskbarQuitButton()
{
InitializeComponent();
LoadIcon();

View file

@ -80,6 +80,9 @@
<Compile Include="Controls\ActionCenterApplicationButton.xaml.cs">
<DependentUpon>ActionCenterApplicationButton.xaml</DependentUpon>
</Compile>
<Compile Include="Controls\ActionCenterClock.xaml.cs">
<DependentUpon>ActionCenterClock.xaml</DependentUpon>
</Compile>
<Compile Include="Controls\ActionCenterKeyboardLayoutButton.xaml.cs">
<DependentUpon>ActionCenterKeyboardLayoutButton.xaml</DependentUpon>
</Compile>
@ -92,6 +95,9 @@
<Compile Include="Controls\ActionCenterPowerSupplyControl.xaml.cs">
<DependentUpon>ActionCenterPowerSupplyControl.xaml</DependentUpon>
</Compile>
<Compile Include="Controls\ActionCenterQuitButton.xaml.cs">
<DependentUpon>ActionCenterQuitButton.xaml</DependentUpon>
</Compile>
<Compile Include="Controls\ActionCenterWirelessNetworkButton.xaml.cs">
<DependentUpon>ActionCenterWirelessNetworkButton.xaml</DependentUpon>
</Compile>
@ -104,8 +110,8 @@
<Compile Include="Controls\TaskbarApplicationInstanceButton.xaml.cs">
<DependentUpon>TaskbarApplicationInstanceButton.xaml</DependentUpon>
</Compile>
<Compile Include="Controls\DateTimeControl.xaml.cs">
<DependentUpon>DateTimeControl.xaml</DependentUpon>
<Compile Include="Controls\TaskbarClock.xaml.cs">
<DependentUpon>TaskbarClock.xaml</DependentUpon>
</Compile>
<Compile Include="Controls\TaskbarKeyboardLayoutButton.xaml.cs">
<DependentUpon>TaskbarKeyboardLayoutButton.xaml</DependentUpon>
@ -119,8 +125,8 @@
<Compile Include="Controls\TaskbarPowerSupplyControl.xaml.cs">
<DependentUpon>TaskbarPowerSupplyControl.xaml</DependentUpon>
</Compile>
<Compile Include="Controls\QuitButton.xaml.cs">
<DependentUpon>QuitButton.xaml</DependentUpon>
<Compile Include="Controls\TaskbarQuitButton.xaml.cs">
<DependentUpon>TaskbarQuitButton.xaml</DependentUpon>
</Compile>
<Compile Include="Controls\TaskbarWirelessNetworkButton.xaml.cs">
<DependentUpon>TaskbarWirelessNetworkButton.xaml</DependentUpon>
@ -169,6 +175,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Controls\ActionCenterClock.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Controls\ActionCenterKeyboardLayoutButton.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@ -185,6 +195,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Controls\ActionCenterQuitButton.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Controls\ActionCenterWirelessNetworkButton.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@ -201,7 +215,7 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Controls\DateTimeControl.xaml">
<Page Include="Controls\TaskbarClock.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
@ -221,7 +235,7 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Controls\QuitButton.xaml">
<Page Include="Controls\TaskbarQuitButton.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>

View file

@ -26,7 +26,7 @@
</ScrollViewer>
<StackPanel Grid.Column="1" x:Name="NotificationStackPanel" Orientation="Horizontal" VerticalAlignment="Stretch" />
<StackPanel Grid.Column="2" x:Name="SystemControlStackPanel" Orientation="Horizontal" VerticalAlignment="Stretch" />
<local:DateTimeControl Grid.Column="3" x:Name="Clock" Foreground="DimGray" Padding="10,0,10,0" />
<local:QuitButton Grid.Column="4" x:Name="QuitButton" />
<local:TaskbarClock Grid.Column="3" x:Name="Clock" Foreground="DimGray" Padding="10,0,10,0" />
<local:TaskbarQuitButton Grid.Column="4" x:Name="QuitButton" />
</Grid>
</Window>

View file

@ -8,6 +8,7 @@
using System.ComponentModel;
using System.Windows;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.UserInterface.Shell;
using SafeExamBrowser.Contracts.UserInterface.Shell.Events;
@ -29,13 +30,10 @@ namespace SafeExamBrowser.UserInterface.Desktop
public Taskbar(ILogger logger)
{
InitializeComponent();
this.logger = logger;
Closing += Taskbar_Closing;
Loaded += (o, args) => InitializeBounds();
QuitButton.Clicked += QuitButton_Clicked;
InitializeComponent();
InitializeTaskbar();
}
public void AddApplicationControl(IApplicationControl control)
@ -94,6 +92,14 @@ namespace SafeExamBrowser.UserInterface.Desktop
});
}
public void InitializeText(IText text)
{
Dispatcher.Invoke(() =>
{
QuitButton.ToolTip = text.Get(TextKey.Shell_QuitButton);
});
}
public new void Show()
{
Dispatcher.Invoke(base.Show);
@ -122,5 +128,12 @@ namespace SafeExamBrowser.UserInterface.Desktop
}
}
}
private void InitializeTaskbar()
{
Closing += Taskbar_Closing;
Loaded += (o, args) => InitializeBounds();
QuitButton.Clicked += QuitButton_Clicked;
}
}
}

View file

@ -12,9 +12,10 @@ using System.Timers;
namespace SafeExamBrowser.UserInterface.Desktop.ViewModels
{
class DateTimeViewModel : INotifyPropertyChanged
internal class DateTimeViewModel : INotifyPropertyChanged
{
private Timer timer;
private readonly bool showSeconds;
public string Date { get; private set; }
public string Time { get; private set; }
@ -22,11 +23,12 @@ namespace SafeExamBrowser.UserInterface.Desktop.ViewModels
public event PropertyChangedEventHandler PropertyChanged;
public DateTimeViewModel()
public DateTimeViewModel(bool showSeconds)
{
timer = new Timer(1000);
timer.Elapsed += Timer_Elapsed;
timer.Start();
this.showSeconds = showSeconds;
this.timer = new Timer(1000);
this.timer.Elapsed += Timer_Elapsed;
this.timer.Start();
}
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
@ -34,7 +36,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.ViewModels
var date = DateTime.Now;
Date = date.ToShortDateString();
Time = date.ToShortTimeString();
Time = showSeconds ? date.ToLongTimeString() : date.ToShortTimeString();
ToolTip = $"{date.ToLongDateString()} {date.ToLongTimeString()}";
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Time)));