SEBWIN-312: Finished first draft of task view.
This commit is contained in:
parent
08bf49b61b
commit
fbe03b86ea
20 changed files with 227 additions and 85 deletions
|
@ -21,13 +21,12 @@ namespace SafeExamBrowser.Applications
|
||||||
private const int ONE_SECOND = 1000;
|
private const int ONE_SECOND = 1000;
|
||||||
|
|
||||||
private ILogger logger;
|
private ILogger logger;
|
||||||
private string name;
|
|
||||||
private IProcess process;
|
private IProcess process;
|
||||||
private Timer timer;
|
private Timer timer;
|
||||||
|
|
||||||
public IconResource Icon { get; }
|
public IconResource Icon { get; }
|
||||||
public InstanceIdentifier Id { get; }
|
public InstanceIdentifier Id { get; }
|
||||||
public string Name { get; }
|
public string Name { get; private set; }
|
||||||
|
|
||||||
public event IconChangedEventHandler IconChanged { add { } remove { } }
|
public event IconChangedEventHandler IconChanged { add { } remove { } }
|
||||||
public event NameChangedEventHandler NameChanged;
|
public event NameChangedEventHandler NameChanged;
|
||||||
|
@ -114,12 +113,12 @@ namespace SafeExamBrowser.Applications
|
||||||
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
|
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
|
||||||
{
|
{
|
||||||
var success = process.TryGetWindowTitle(out var title);
|
var success = process.TryGetWindowTitle(out var title);
|
||||||
var hasChanged = name?.Equals(title, StringComparison.Ordinal) != true;
|
var hasChanged = Name?.Equals(title, StringComparison.Ordinal) != true;
|
||||||
|
|
||||||
if (success && hasChanged)
|
if (success && hasChanged)
|
||||||
{
|
{
|
||||||
name = title;
|
Name = title;
|
||||||
NameChanged?.Invoke(name);
|
NameChanged?.Invoke(Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
timer.Start();
|
timer.Start();
|
||||||
|
|
|
@ -194,8 +194,9 @@ namespace SafeExamBrowser.Browser
|
||||||
|
|
||||||
private void Control_TitleChanged(string title)
|
private void Control_TitleChanged(string title)
|
||||||
{
|
{
|
||||||
window.UpdateTitle(title);
|
Name = title;
|
||||||
NameChanged?.Invoke(title);
|
window.UpdateTitle(Name);
|
||||||
|
NameChanged?.Invoke(Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DisplayHandler_FaviconChanged(string uri)
|
private void DisplayHandler_FaviconChanged(string uri)
|
||||||
|
|
|
@ -24,6 +24,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
||||||
private ClientContext context;
|
private ClientContext context;
|
||||||
private Mock<ILogger> logger;
|
private Mock<ILogger> logger;
|
||||||
private Mock<ITaskbar> taskbar;
|
private Mock<ITaskbar> taskbar;
|
||||||
|
private Mock<ITaskView> taskView;
|
||||||
private Mock<IUserInterfaceFactory> uiFactory;
|
private Mock<IUserInterfaceFactory> uiFactory;
|
||||||
|
|
||||||
private BrowserOperation sut;
|
private BrowserOperation sut;
|
||||||
|
@ -36,11 +37,12 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
||||||
context = new ClientContext();
|
context = new ClientContext();
|
||||||
logger = new Mock<ILogger>();
|
logger = new Mock<ILogger>();
|
||||||
taskbar = new Mock<ITaskbar>();
|
taskbar = new Mock<ITaskbar>();
|
||||||
|
taskView = new Mock<ITaskView>();
|
||||||
uiFactory = new Mock<IUserInterfaceFactory>();
|
uiFactory = new Mock<IUserInterfaceFactory>();
|
||||||
|
|
||||||
context.Browser = browser.Object;
|
context.Browser = browser.Object;
|
||||||
|
|
||||||
sut = new BrowserOperation(actionCenter.Object, context, logger.Object, taskbar.Object, uiFactory.Object);
|
sut = new BrowserOperation(actionCenter.Object, context, logger.Object, taskbar.Object, taskView.Object, uiFactory.Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
@ -59,5 +61,11 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
||||||
sut.Revert();
|
sut.Revert();
|
||||||
browser.Verify(c => c.Terminate(), Times.Once);
|
browser.Verify(c => c.Terminate(), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TODO()
|
||||||
|
{
|
||||||
|
// TODO: Test initialization of task view!
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,7 @@ namespace SafeExamBrowser.Client
|
||||||
private IRuntimeProxy runtimeProxy;
|
private IRuntimeProxy runtimeProxy;
|
||||||
private ISystemInfo systemInfo;
|
private ISystemInfo systemInfo;
|
||||||
private ITaskbar taskbar;
|
private ITaskbar taskbar;
|
||||||
|
private ITaskView taskView;
|
||||||
private IText text;
|
private IText text;
|
||||||
private ITextResource textResource;
|
private ITextResource textResource;
|
||||||
private IUserInterfaceFactory uiFactory;
|
private IUserInterfaceFactory uiFactory;
|
||||||
|
@ -94,6 +95,7 @@ namespace SafeExamBrowser.Client
|
||||||
uiFactory = BuildUserInterfaceFactory();
|
uiFactory = BuildUserInterfaceFactory();
|
||||||
runtimeProxy = new RuntimeProxy(runtimeHostUri, new ProxyObjectFactory(), ModuleLogger(nameof(RuntimeProxy)), Interlocutor.Client);
|
runtimeProxy = new RuntimeProxy(runtimeHostUri, new ProxyObjectFactory(), ModuleLogger(nameof(RuntimeProxy)), Interlocutor.Client);
|
||||||
taskbar = BuildTaskbar();
|
taskbar = BuildTaskbar();
|
||||||
|
taskView = BuildTaskView();
|
||||||
|
|
||||||
var processFactory = new ProcessFactory(ModuleLogger(nameof(ProcessFactory)));
|
var processFactory = new ProcessFactory(ModuleLogger(nameof(ProcessFactory)));
|
||||||
var applicationFactory = new ApplicationFactory(ModuleLogger(nameof(ApplicationFactory)), processFactory);
|
var applicationFactory = new ApplicationFactory(ModuleLogger(nameof(ApplicationFactory)), processFactory);
|
||||||
|
@ -197,7 +199,7 @@ namespace SafeExamBrowser.Client
|
||||||
{
|
{
|
||||||
var moduleLogger = ModuleLogger(nameof(BrowserApplication));
|
var moduleLogger = ModuleLogger(nameof(BrowserApplication));
|
||||||
var browser = new BrowserApplication(context.AppConfig, context.Settings.Browser, messageBox, moduleLogger, text, uiFactory);
|
var browser = new BrowserApplication(context.AppConfig, context.Settings.Browser, messageBox, moduleLogger, text, uiFactory);
|
||||||
var operation = new BrowserOperation(actionCenter, context, logger, taskbar, uiFactory);
|
var operation = new BrowserOperation(actionCenter, context, logger, taskbar, taskView, uiFactory);
|
||||||
|
|
||||||
context.Browser = browser;
|
context.Browser = browser;
|
||||||
|
|
||||||
|
@ -242,7 +244,6 @@ namespace SafeExamBrowser.Client
|
||||||
var logInfo = new LogNotificationInfo(text);
|
var logInfo = new LogNotificationInfo(text);
|
||||||
var logController = new LogNotificationController(logger, uiFactory);
|
var logController = new LogNotificationController(logger, uiFactory);
|
||||||
var powerSupply = new PowerSupply(ModuleLogger(nameof(PowerSupply)));
|
var powerSupply = new PowerSupply(ModuleLogger(nameof(PowerSupply)));
|
||||||
var taskView = BuildTaskView();
|
|
||||||
var wirelessAdapter = new WirelessAdapter(ModuleLogger(nameof(WirelessAdapter)));
|
var wirelessAdapter = new WirelessAdapter(ModuleLogger(nameof(WirelessAdapter)));
|
||||||
var operation = new ShellOperation(
|
var operation = new ShellOperation(
|
||||||
actionCenter,
|
actionCenter,
|
||||||
|
|
|
@ -20,6 +20,7 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
private IActionCenter actionCenter;
|
private IActionCenter actionCenter;
|
||||||
private ILogger logger;
|
private ILogger logger;
|
||||||
private ITaskbar taskbar;
|
private ITaskbar taskbar;
|
||||||
|
private ITaskView taskView;
|
||||||
private IUserInterfaceFactory uiFactory;
|
private IUserInterfaceFactory uiFactory;
|
||||||
|
|
||||||
public override event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
public override event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||||
|
@ -30,11 +31,13 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
ClientContext context,
|
ClientContext context,
|
||||||
ILogger logger,
|
ILogger logger,
|
||||||
ITaskbar taskbar,
|
ITaskbar taskbar,
|
||||||
|
ITaskView taskView,
|
||||||
IUserInterfaceFactory uiFactory) : base(context)
|
IUserInterfaceFactory uiFactory) : base(context)
|
||||||
{
|
{
|
||||||
this.actionCenter = actionCenter;
|
this.actionCenter = actionCenter;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.taskbar = taskbar;
|
this.taskbar = taskbar;
|
||||||
|
this.taskView = taskView;
|
||||||
this.uiFactory = uiFactory;
|
this.uiFactory = uiFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,6 +58,8 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
taskbar.AddApplicationControl(uiFactory.CreateApplicationControl(Context.Browser, Location.Taskbar), true);
|
taskbar.AddApplicationControl(uiFactory.CreateApplicationControl(Context.Browser, Location.Taskbar), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
taskView.Add(Context.Browser);
|
||||||
|
|
||||||
return OperationResult.Success;
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,12 @@
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls"
|
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">
|
mc:Ignorable="d" Title="ActionCenter" Height="1000" Width="400" Background="{DynamicResource BackgroundTransparentBrush}"
|
||||||
|
AllowsTransparency="True" WindowStyle="None" Topmost="True" ResizeMode="NoResize">
|
||||||
<Window.Resources>
|
<Window.Resources>
|
||||||
<ResourceDictionary>
|
<ResourceDictionary>
|
||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<ResourceDictionary Source="./Templates/Colors.xaml" />
|
||||||
<ResourceDictionary Source="./Templates/ScrollViewers.xaml" />
|
<ResourceDictionary Source="./Templates/ScrollViewers.xaml" />
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
|
|
|
@ -20,8 +20,8 @@
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<TextBlock Grid.Row="0" x:Name="ApplicationName" Background="#99D3D3D3" FontWeight="Bold" Padding="5" TextAlignment="Center" />
|
<TextBlock Grid.Row="0" x:Name="ApplicationName" Background="{StaticResource BackgroundTransparentEmphasisBrush}" FontWeight="Bold" Padding="5" TextAlignment="Center" />
|
||||||
<ContentControl Grid.Row="1" x:Name="ApplicationButton" FontWeight="Bold" />
|
<ContentControl Grid.Row="1" x:Name="ApplicationButton" FontWeight="Bold" />
|
||||||
<StackPanel Grid.Row="2" x:Name="InstancePanel" Background="#99D3D3D3" Orientation="Vertical" />
|
<StackPanel Grid.Row="2" x:Name="InstancePanel" Background="{StaticResource BackgroundTransparentEmphasisBrush}" Orientation="Vertical" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
<UserControl x:Class="SafeExamBrowser.UserInterface.Desktop.Controls.TaskViewInstanceControl"
|
||||||
|
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">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<ResourceDictionary>
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<ResourceDictionary Source="../Templates/Colors.xaml" />
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
</ResourceDictionary>
|
||||||
|
</UserControl.Resources>
|
||||||
|
<Grid Margin="5" Height="150" Width="250">
|
||||||
|
<Border Name="Border" Background="{StaticResource BackgroundTransparentEmphasisBrush}" BorderBrush="DarkGray" BorderThickness="2" Visibility="Hidden" />
|
||||||
|
<StackPanel HorizontalAlignment="Center" Orientation="Vertical" VerticalAlignment="Center">
|
||||||
|
<ContentControl Name="Icon" MaxWidth="40" />
|
||||||
|
<TextBlock Name="Title" Margin="10" Foreground="{StaticResource PrimaryTextBrush}" TextTrimming="CharacterEllipsis" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* 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.Applications.Contracts;
|
||||||
|
using SafeExamBrowser.Core.Contracts;
|
||||||
|
using SafeExamBrowser.UserInterface.Shared.Utilities;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.UserInterface.Desktop.Controls
|
||||||
|
{
|
||||||
|
public partial class TaskViewInstanceControl : UserControl
|
||||||
|
{
|
||||||
|
private IApplicationInstance instance;
|
||||||
|
|
||||||
|
internal InstanceIdentifier Id => instance.Id;
|
||||||
|
|
||||||
|
public TaskViewInstanceControl(IApplicationInstance instance)
|
||||||
|
{
|
||||||
|
this.instance = instance;
|
||||||
|
|
||||||
|
InitializeComponent();
|
||||||
|
InitializeControl();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Activate()
|
||||||
|
{
|
||||||
|
instance.Activate();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Deselect()
|
||||||
|
{
|
||||||
|
Border.Visibility = Visibility.Hidden;
|
||||||
|
Icon.MaxWidth = 40;
|
||||||
|
Title.FontWeight = FontWeights.Normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Select()
|
||||||
|
{
|
||||||
|
Border.Visibility = Visibility.Visible;
|
||||||
|
Icon.MaxWidth = 50;
|
||||||
|
Title.FontWeight = FontWeights.SemiBold;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeControl()
|
||||||
|
{
|
||||||
|
Icon.Content = IconResourceLoader.Load(instance.Icon);
|
||||||
|
Title.Text = instance.Name;
|
||||||
|
|
||||||
|
instance.IconChanged += Instance_IconChanged;
|
||||||
|
instance.NameChanged += Instance_NameChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Instance_NameChanged(string name)
|
||||||
|
{
|
||||||
|
Dispatcher.InvokeAsync(() => Title.Text = name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Instance_IconChanged(IconResource icon)
|
||||||
|
{
|
||||||
|
Dispatcher.InvokeAsync(() => Icon.Content = IconResourceLoader.Load(instance.Icon));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,7 @@
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop"
|
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop"
|
||||||
mc:Ignorable="d" Title="{Binding Path=WindowTitle}" Background="Black" Foreground="White" Height="500" Width="1100" MinHeight="350"
|
mc:Ignorable="d" Title="{Binding Path=WindowTitle}" Background="Black" Foreground="White" Height="750" Width="1000" MinHeight="350"
|
||||||
MinWidth="350" WindowStartupLocation="CenterScreen" Icon="./Images/LogNotification.ico">
|
MinWidth="350" WindowStartupLocation="CenterScreen" Icon="./Images/LogNotification.ico">
|
||||||
<Window.Resources>
|
<Window.Resources>
|
||||||
<ResourceDictionary>
|
<ResourceDictionary>
|
||||||
|
|
|
@ -142,6 +142,9 @@
|
||||||
<Compile Include="Controls\TaskbarWirelessNetworkControl.xaml.cs">
|
<Compile Include="Controls\TaskbarWirelessNetworkControl.xaml.cs">
|
||||||
<DependentUpon>TaskbarWirelessNetworkControl.xaml</DependentUpon>
|
<DependentUpon>TaskbarWirelessNetworkControl.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Controls\TaskViewInstanceControl.xaml.cs">
|
||||||
|
<DependentUpon>TaskViewInstanceControl.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Include="LockScreen.xaml.cs">
|
<Compile Include="LockScreen.xaml.cs">
|
||||||
<DependentUpon>LockScreen.xaml</DependentUpon>
|
<DependentUpon>LockScreen.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
@ -314,6 +317,10 @@
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</Resource>
|
</Resource>
|
||||||
|
<Page Include="Controls\TaskViewInstanceControl.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
<Page Include="LockScreen.xaml">
|
<Page Include="LockScreen.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
|
|
@ -4,8 +4,15 @@
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop"
|
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop"
|
||||||
mc:Ignorable="d" AllowsTransparency="True" Background="#AA000000" BorderBrush="DodgerBlue" BorderThickness="1" Title="TaskView"
|
mc:Ignorable="d" AllowsTransparency="True" Background="{DynamicResource BackgroundTransparentBrush}" BorderBrush="DodgerBlue" BorderThickness="1"
|
||||||
Topmost="True" Height="450" SizeToContent="WidthAndHeight" Width="800" WindowStartupLocation="CenterScreen" WindowStyle="None">
|
Title="TaskView" Topmost="True" Height="450" SizeToContent="WidthAndHeight" Width="800" WindowStartupLocation="CenterScreen" WindowStyle="None">
|
||||||
|
<Window.Resources>
|
||||||
|
<ResourceDictionary>
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<ResourceDictionary Source="./Templates/Colors.xaml" />
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
</ResourceDictionary>
|
||||||
|
</Window.Resources>
|
||||||
<Grid>
|
<Grid>
|
||||||
<StackPanel Name="Rows" Margin="10" Orientation="Vertical" />
|
<StackPanel Name="Rows" Margin="10" Orientation="Vertical" />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
|
@ -11,23 +11,24 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Documents;
|
|
||||||
using System.Windows.Media;
|
|
||||||
using SafeExamBrowser.Applications.Contracts;
|
using SafeExamBrowser.Applications.Contracts;
|
||||||
using SafeExamBrowser.Core.Contracts;
|
|
||||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||||
using SafeExamBrowser.UserInterface.Shared.Utilities;
|
using SafeExamBrowser.UserInterface.Desktop.Controls;
|
||||||
|
|
||||||
namespace SafeExamBrowser.UserInterface.Desktop
|
namespace SafeExamBrowser.UserInterface.Desktop
|
||||||
{
|
{
|
||||||
public partial class TaskView : Window, ITaskView
|
public partial class TaskView : Window, ITaskView
|
||||||
{
|
{
|
||||||
private IList<IApplicationInstance> instances;
|
private LinkedListNode<TaskViewInstanceControl> current;
|
||||||
|
private LinkedList<TaskViewInstanceControl> controls;
|
||||||
|
private List<IApplicationInstance> instances;
|
||||||
|
|
||||||
public TaskView()
|
public TaskView()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
controls = new LinkedList<TaskViewInstanceControl>();
|
||||||
instances = new List<IApplicationInstance>();
|
instances = new List<IApplicationInstance>();
|
||||||
|
|
||||||
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Add(IApplication application)
|
public void Add(IApplication application)
|
||||||
|
@ -44,61 +45,84 @@ namespace SafeExamBrowser.UserInterface.Desktop
|
||||||
|
|
||||||
private void Application_InstanceStarted(IApplicationInstance instance)
|
private void Application_InstanceStarted(IApplicationInstance instance)
|
||||||
{
|
{
|
||||||
Dispatcher.InvokeAsync(() =>
|
Dispatcher.InvokeAsync(() => Add(instance));
|
||||||
{
|
|
||||||
instance.IconChanged += Instance_IconChanged;
|
|
||||||
instance.NameChanged += Instance_NameChanged;
|
|
||||||
instance.Terminated += Instance_Terminated;
|
|
||||||
|
|
||||||
instances.Add(instance);
|
|
||||||
Update();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Activator_Deactivated()
|
private void Activator_Deactivated()
|
||||||
{
|
{
|
||||||
Dispatcher.InvokeAsync(Hide);
|
Dispatcher.InvokeAsync(ActivateAndHide);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Activator_Next()
|
private void Activator_Next()
|
||||||
{
|
{
|
||||||
Dispatcher.InvokeAsync(ShowConditional);
|
Dispatcher.InvokeAsync(SelectNext);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Activator_Previous()
|
private void Activator_Previous()
|
||||||
{
|
{
|
||||||
Dispatcher.InvokeAsync(ShowConditional);
|
Dispatcher.InvokeAsync(SelectPrevious);
|
||||||
}
|
|
||||||
|
|
||||||
private void Instance_IconChanged(IconResource icon)
|
|
||||||
{
|
|
||||||
// TODO Dispatcher.InvokeAsync(...);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Instance_NameChanged(string name)
|
|
||||||
{
|
|
||||||
// TODO Dispatcher.InvokeAsync(...);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Instance_Terminated(InstanceIdentifier id)
|
private void Instance_Terminated(InstanceIdentifier id)
|
||||||
{
|
{
|
||||||
Dispatcher.InvokeAsync(() =>
|
Dispatcher.InvokeAsync(() => Remove(id));
|
||||||
{
|
}
|
||||||
var instance = instances.FirstOrDefault(i => i.Id == id);
|
|
||||||
|
|
||||||
if (instance != default(IApplicationInstance))
|
private void ActivateAndHide()
|
||||||
{
|
{
|
||||||
instances.Remove(instance);
|
Activate();
|
||||||
Update();
|
current?.Value.Activate();
|
||||||
}
|
Hide();
|
||||||
});
|
}
|
||||||
|
|
||||||
|
private void Add(IApplicationInstance instance)
|
||||||
|
{
|
||||||
|
instance.Terminated += Instance_Terminated;
|
||||||
|
instances.Add(instance);
|
||||||
|
Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Remove(InstanceIdentifier id)
|
||||||
|
{
|
||||||
|
var instance = instances.FirstOrDefault(i => i.Id == id);
|
||||||
|
|
||||||
|
if (instance != default(IApplicationInstance))
|
||||||
|
{
|
||||||
|
instances.Remove(instance);
|
||||||
|
Update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SelectNext()
|
||||||
|
{
|
||||||
|
ShowConditional();
|
||||||
|
|
||||||
|
if (current != null)
|
||||||
|
{
|
||||||
|
current.Value.Deselect();
|
||||||
|
current = current.Next ?? controls.First;
|
||||||
|
current.Value.Select();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SelectPrevious()
|
||||||
|
{
|
||||||
|
ShowConditional();
|
||||||
|
|
||||||
|
if (current != null)
|
||||||
|
{
|
||||||
|
current.Value.Deselect();
|
||||||
|
current = current.Previous ?? controls.Last;
|
||||||
|
current.Value.Select();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShowConditional()
|
private void ShowConditional()
|
||||||
{
|
{
|
||||||
if (Visibility != Visibility.Visible && instances.Any())
|
if (instances.Any() && Visibility != Visibility.Visible)
|
||||||
{
|
{
|
||||||
Show();
|
Show();
|
||||||
|
Activate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,6 +131,7 @@ namespace SafeExamBrowser.UserInterface.Desktop
|
||||||
var max = Math.Ceiling(Math.Sqrt(instances.Count));
|
var max = Math.Ceiling(Math.Sqrt(instances.Count));
|
||||||
var stack = new Stack<IApplicationInstance>(instances);
|
var stack = new Stack<IApplicationInstance>(instances);
|
||||||
|
|
||||||
|
controls.Clear();
|
||||||
Rows.Children.Clear();
|
Rows.Children.Clear();
|
||||||
|
|
||||||
for (var rowCount = 0; rowCount < max && stack.Any(); rowCount++)
|
for (var rowCount = 0; rowCount < max && stack.Any(); rowCount++)
|
||||||
|
@ -118,12 +143,16 @@ namespace SafeExamBrowser.UserInterface.Desktop
|
||||||
for (var columnIndex = 0; columnIndex < max && stack.Any(); columnIndex++)
|
for (var columnIndex = 0; columnIndex < max && stack.Any(); columnIndex++)
|
||||||
{
|
{
|
||||||
var instance = stack.Pop();
|
var instance = stack.Pop();
|
||||||
var control = BuildInstanceControl(instance);
|
var control = new TaskViewInstanceControl(instance);
|
||||||
|
|
||||||
|
controls.AddLast(control);
|
||||||
row.Children.Add(control);
|
row.Children.Add(control);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
current = controls.First;
|
||||||
|
current?.Value.Select();
|
||||||
|
|
||||||
UpdateLayout();
|
UpdateLayout();
|
||||||
|
|
||||||
Left = (SystemParameters.WorkArea.Width - Width) / 2 + SystemParameters.WorkArea.Left;
|
Left = (SystemParameters.WorkArea.Width - Width) / 2 + SystemParameters.WorkArea.Left;
|
||||||
|
@ -134,28 +163,5 @@ namespace SafeExamBrowser.UserInterface.Desktop
|
||||||
Hide();
|
Hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private UIElement BuildInstanceControl(IApplicationInstance instance)
|
|
||||||
{
|
|
||||||
var border = new Border();
|
|
||||||
var stackPanel = new StackPanel();
|
|
||||||
var icon = IconResourceLoader.Load(instance.Icon);
|
|
||||||
|
|
||||||
border.BorderBrush = Brushes.White;
|
|
||||||
border.BorderThickness = new Thickness(1);
|
|
||||||
border.Height = 150;
|
|
||||||
border.Margin = new Thickness(5);
|
|
||||||
border.Padding = new Thickness(2);
|
|
||||||
border.Width = 250;
|
|
||||||
border.Child = stackPanel;
|
|
||||||
|
|
||||||
stackPanel.HorizontalAlignment = HorizontalAlignment.Center;
|
|
||||||
stackPanel.Orientation = Orientation.Vertical;
|
|
||||||
stackPanel.VerticalAlignment = VerticalAlignment.Center;
|
|
||||||
stackPanel.Children.Add(new ContentControl { Content = icon, MaxWidth = 50 });
|
|
||||||
stackPanel.Children.Add(new TextBlock(new Run($"Instance {instance.Name ?? "NULL"}") { Foreground = Brushes.White, FontWeight = FontWeights.Bold }));
|
|
||||||
|
|
||||||
return border;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,12 @@
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls"
|
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls"
|
||||||
xmlns:s="clr-namespace:System;assembly=mscorlib"
|
xmlns:s="clr-namespace:System;assembly=mscorlib"
|
||||||
mc:Ignorable="d" Title="Taskbar" Background="#FFF0F0F0" Height="40" Width="750" WindowStyle="None" Topmost="True" ResizeMode="NoResize" Icon="./Images/SafeExamBrowser.ico">
|
mc:Ignorable="d" Title="Taskbar" Background="{DynamicResource BackgroundBrush}" Height="40" Width="750" WindowStyle="None" Topmost="True"
|
||||||
|
ResizeMode="NoResize" Icon="./Images/SafeExamBrowser.ico">
|
||||||
<Window.Resources>
|
<Window.Resources>
|
||||||
<ResourceDictionary>
|
<ResourceDictionary>
|
||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<ResourceDictionary Source="./Templates/Colors.xaml" />
|
||||||
<ResourceDictionary Source="./Templates/ScrollViewers.xaml" />
|
<ResourceDictionary Source="./Templates/ScrollViewers.xaml" />
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
|
@ -26,7 +28,7 @@
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
<StackPanel Grid.Column="1" x:Name="NotificationStackPanel" Orientation="Horizontal" VerticalAlignment="Stretch" />
|
<StackPanel Grid.Column="1" x:Name="NotificationStackPanel" Orientation="Horizontal" VerticalAlignment="Stretch" />
|
||||||
<StackPanel Grid.Column="2" x:Name="SystemControlStackPanel" Orientation="Horizontal" VerticalAlignment="Stretch" />
|
<StackPanel Grid.Column="2" x:Name="SystemControlStackPanel" Orientation="Horizontal" VerticalAlignment="Stretch" />
|
||||||
<local:TaskbarClock Grid.Column="3" x:Name="Clock" Foreground="DimGray" Padding="10,0,10,0" />
|
<local:TaskbarClock Grid.Column="3" x:Name="Clock" Foreground="{StaticResource SecondaryTextBrush}" Padding="10,0,10,0" />
|
||||||
<local:TaskbarQuitButton Grid.Column="4" x:Name="QuitButton" />
|
<local:TaskbarQuitButton Grid.Column="4" x:Name="QuitButton" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Window>
|
</Window>
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
<SolidColorBrush x:Key="BackgroundBrush">#FFF0F0F0</SolidColorBrush>
|
|
||||||
<SolidColorBrush x:Key="ActionCenterDarkBrush">#AA808080</SolidColorBrush>
|
<SolidColorBrush x:Key="ActionCenterDarkBrush">#AA808080</SolidColorBrush>
|
||||||
|
<SolidColorBrush x:Key="BackgroundBrush">#FFF0F0F0</SolidColorBrush>
|
||||||
|
<SolidColorBrush x:Key="BackgroundTransparentBrush">#EEF0F0F0</SolidColorBrush>
|
||||||
|
<SolidColorBrush x:Key="BackgroundTransparentEmphasisBrush">#99D3D3D3</SolidColorBrush>
|
||||||
|
<SolidColorBrush x:Key="PrimaryTextBrush">Black</SolidColorBrush>
|
||||||
|
<SolidColorBrush x:Key="SecondaryTextBrush">DimGray</SolidColorBrush>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
|
@ -4,7 +4,7 @@
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Mobile"
|
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Mobile"
|
||||||
mc:Ignorable="d" Title="{Binding Path=WindowTitle}" Background="Black" Foreground="White" Height="500" Width="1100" MinHeight="350"
|
mc:Ignorable="d" Title="{Binding Path=WindowTitle}" Background="Black" Foreground="White" Height="750" Width="1000" MinHeight="350"
|
||||||
MinWidth="350" WindowState="Maximized" WindowStartupLocation="CenterScreen" Icon="./Images/LogNotification.ico">
|
MinWidth="350" WindowState="Maximized" WindowStartupLocation="CenterScreen" Icon="./Images/LogNotification.ico">
|
||||||
<Window.Resources>
|
<Window.Resources>
|
||||||
<ResourceDictionary>
|
<ResourceDictionary>
|
||||||
|
|
|
@ -342,7 +342,7 @@ namespace SafeExamBrowser.WindowsApi
|
||||||
|
|
||||||
public void RestoreWindow(IntPtr window)
|
public void RestoreWindow(IntPtr window)
|
||||||
{
|
{
|
||||||
User32.ShowWindow(window, (int)ShowWindowCommand.Restore);
|
User32.ShowWindow(window, (int) ShowWindowCommand.Restore);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ResumeThread(int threadId)
|
public bool ResumeThread(int threadId)
|
||||||
|
|
|
@ -69,15 +69,18 @@ namespace SafeExamBrowser.WindowsApi
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var success = User32.BringWindowToTop(process.MainWindowHandle);
|
var success = true;
|
||||||
var placement = new WINDOWPLACEMENT();
|
var placement = new WINDOWPLACEMENT();
|
||||||
|
|
||||||
|
success &= User32.BringWindowToTop(process.MainWindowHandle);
|
||||||
|
success &= User32.SetForegroundWindow(process.MainWindowHandle);
|
||||||
|
|
||||||
placement.length = Marshal.SizeOf(placement);
|
placement.length = Marshal.SizeOf(placement);
|
||||||
User32.GetWindowPlacement(process.MainWindowHandle, ref placement);
|
User32.GetWindowPlacement(process.MainWindowHandle, ref placement);
|
||||||
|
|
||||||
if (placement.showCmd == (int) ShowWindowCommand.ShowMinimized)
|
if (placement.showCmd == (int) ShowWindowCommand.ShowMinimized)
|
||||||
{
|
{
|
||||||
success &= User32.ShowWindow(process.MainWindowHandle, (int) ShowWindowCommand.Restore);
|
success &= User32.ShowWindowAsync(process.MainWindowHandle, (int) ShowWindowCommand.Restore);
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
|
|
|
@ -59,6 +59,7 @@ namespace SafeExamBrowser.WindowsApi
|
||||||
|
|
||||||
logger.Info($"Attempting to start process '{path}'...");
|
logger.Info($"Attempting to start process '{path}'...");
|
||||||
|
|
||||||
|
// TODO: Fails for certain processes, whereas Process.Start() does not -> use different API?! Use (declare?) CreateProcessW / CreateProcessA?
|
||||||
var success = Kernel32.CreateProcess(null, commandLine, IntPtr.Zero, IntPtr.Zero, true, Constant.NORMAL_PRIORITY_CLASS, IntPtr.Zero, null, ref startupInfo, ref processInfo);
|
var success = Kernel32.CreateProcess(null, commandLine, IntPtr.Zero, IntPtr.Zero, true, Constant.NORMAL_PRIORITY_CLASS, IntPtr.Zero, null, ref startupInfo, ref processInfo);
|
||||||
|
|
||||||
if (!success)
|
if (!success)
|
||||||
|
|
|
@ -83,6 +83,9 @@ namespace SafeExamBrowser.WindowsApi
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
internal static extern IntPtr SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
|
internal static extern IntPtr SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
|
internal static extern bool SetForegroundWindow(IntPtr hWnd);
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
internal static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, EventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
|
internal static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, EventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
|
||||||
|
|
||||||
|
@ -92,6 +95,9 @@ namespace SafeExamBrowser.WindowsApi
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
internal static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
|
internal static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
|
internal static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
internal static extern bool SwitchDesktop(IntPtr hDesktop);
|
internal static extern bool SwitchDesktop(IntPtr hDesktop);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue