Continued implementation of browser window, i.e. added basic browser functionality like address bar, refresh and navigation.

This commit is contained in:
Damian Büchel 2017-07-31 20:22:53 +02:00
parent 714d300758
commit 5c365f02b0
23 changed files with 391 additions and 70 deletions

View file

@ -13,6 +13,7 @@ using CefSharp;
using SafeExamBrowser.Contracts.Behaviour; using SafeExamBrowser.Contracts.Behaviour;
using SafeExamBrowser.Contracts.Configuration; using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.Configuration.Settings; using SafeExamBrowser.Contracts.Configuration.Settings;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.UserInterface; using SafeExamBrowser.Contracts.UserInterface;
namespace SafeExamBrowser.Browser namespace SafeExamBrowser.Browser
@ -23,10 +24,12 @@ namespace SafeExamBrowser.Browser
private IList<IApplicationInstance> instances = new List<IApplicationInstance>(); private IList<IApplicationInstance> instances = new List<IApplicationInstance>();
private ISettings settings; private ISettings settings;
private IUserInterfaceFactory uiFactory; private IUserInterfaceFactory uiFactory;
private IText text;
public BrowserApplicationController(ISettings settings, IUserInterfaceFactory uiFactory) public BrowserApplicationController(ISettings settings, IText text, IUserInterfaceFactory uiFactory)
{ {
this.settings = settings; this.settings = settings;
this.text = text;
this.uiFactory = uiFactory; this.uiFactory = uiFactory;
} }
@ -56,7 +59,7 @@ namespace SafeExamBrowser.Browser
{ {
foreach (var instance in instances) foreach (var instance in instances)
{ {
instance.OnTerminated -= Instance_OnTerminated; instance.Terminated -= Instance_Terminated;
instance.Window.Close(); instance.Window.Close();
} }
@ -65,17 +68,13 @@ namespace SafeExamBrowser.Browser
private void CreateNewInstance() private void CreateNewInstance()
{ {
var control = new BrowserControl("www.duckduckgo.com"); var instance = new BrowserApplicationInstance(settings.Browser, text, uiFactory, instances.Count == 0);
var window = uiFactory.CreateBrowserWindow(control, settings.Browser);
var instance = new BrowserApplicationInstance("DuckDuckGo");
instance.RegisterWindow(window);
instance.OnTerminated += Instance_OnTerminated;
button.RegisterInstance(instance); button.RegisterInstance(instance);
instances.Add(instance); instances.Add(instance);
window.Show(); instance.Terminated += Instance_Terminated;
instance.Window.Show();
} }
private void Button_OnClick(Guid? instanceId = null) private void Button_OnClick(Guid? instanceId = null)
@ -90,7 +89,7 @@ namespace SafeExamBrowser.Browser
} }
} }
private void Instance_OnTerminated(Guid id) private void Instance_Terminated(Guid id)
{ {
instances.Remove(instances.FirstOrDefault(i => i.Id == id)); instances.Remove(instances.FirstOrDefault(i => i.Id == id));
} }

View file

@ -8,28 +8,70 @@
using System; using System;
using SafeExamBrowser.Contracts.Configuration; using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.Configuration.Settings;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.UserInterface; using SafeExamBrowser.Contracts.UserInterface;
namespace SafeExamBrowser.Browser namespace SafeExamBrowser.Browser
{ {
public class BrowserApplicationInstance : IApplicationInstance public class BrowserApplicationInstance : IApplicationInstance
{ {
private IBrowserControl control;
private IBrowserWindow window;
public Guid Id { get; private set; } public Guid Id { get; private set; }
public string Name { get; private set; } public string Name { get; private set; }
public IWindow Window { get; private set; } public IWindow Window { get { return window; } }
public event TerminationEventHandler OnTerminated; public event TerminationEventHandler Terminated;
public event NameChangedEventHandler NameChanged;
public BrowserApplicationInstance(string name) public BrowserApplicationInstance(IBrowserSettings settings, IText text, IUserInterfaceFactory uiFactory, bool isMainInstance)
{ {
Id = Guid.NewGuid(); Id = Guid.NewGuid();
Name = name;
control = new BrowserControl(settings, text);
control.AddressChanged += Control_AddressChanged;
control.TitleChanged += Control_TitleChanged;
window = uiFactory.CreateBrowserWindow(control, settings);
window.IsMainWindow = isMainInstance;
window.Closing += () => Terminated?.Invoke(Id);
window.AddressChanged += Window_AddressChanged;
window.ReloadRequested += Window_ReloadRequested;
window.BackwardNavigationRequested += Window_BackwardNavigationRequested;
window.ForwardNavigationRequested += Window_ForwardNavigationRequested;
} }
public void RegisterWindow(IWindow window) private void Control_AddressChanged(string address)
{ {
Window = window; window.UpdateAddress(address);
Window.OnClose += () => OnTerminated?.Invoke(Id); }
private void Control_TitleChanged(string title)
{
window.UpdateTitle(title);
NameChanged?.Invoke(title);
}
private void Window_AddressChanged(string address)
{
control.NavigateTo(address);
}
private void Window_ReloadRequested()
{
control.Reload();
}
private void Window_BackwardNavigationRequested()
{
control.NavigateBackwards();
}
private void Window_ForwardNavigationRequested()
{
control.NavigateForwards();
} }
} }
} }

View file

@ -0,0 +1,62 @@
/*
* Copyright (c) 2017 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 CefSharp;
using SafeExamBrowser.Contracts.I18n;
using IBrowserSettings = SafeExamBrowser.Contracts.Configuration.Settings.IBrowserSettings;
namespace SafeExamBrowser.Browser
{
/// <remarks>
/// See https://cefsharp.github.io/api/57.0.0/html/T_CefSharp_IContextMenuHandler.htm.
/// </remarks>
internal class BrowserContextMenuHandler : IContextMenuHandler
{
private const int DEV_CONSOLE_COMMAND = (int) CefMenuCommand.UserFirst + 1;
private IBrowserSettings settings;
private IText text;
public BrowserContextMenuHandler(IBrowserSettings settings, IText text)
{
this.settings = settings;
this.text = text;
}
public void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model)
{
model.Clear();
if (settings.AllowDeveloperConsole)
{
model.AddItem((CefMenuCommand) DEV_CONSOLE_COMMAND, text.Get(Key.Browser_ShowDeveloperConsole));
}
}
public bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags)
{
if ((int) commandId == DEV_CONSOLE_COMMAND)
{
browser.ShowDevTools();
return true;
}
return false;
}
public void OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame)
{
}
public bool RunContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model, IRunContextMenuCallback callback)
{
return false;
}
}
}

View file

@ -6,17 +6,70 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
using System.Windows.Forms; using System;
using CefSharp.WinForms; using CefSharp.WinForms;
using SafeExamBrowser.Contracts.I18n;
using SafeExamBrowser.Contracts.UserInterface; using SafeExamBrowser.Contracts.UserInterface;
using IBrowserSettings = SafeExamBrowser.Contracts.Configuration.Settings.IBrowserSettings;
namespace SafeExamBrowser.Browser namespace SafeExamBrowser.Browser
{ {
class BrowserControl : ChromiumWebBrowser, IBrowserControl class BrowserControl : ChromiumWebBrowser, IBrowserControl
{ {
public BrowserControl(string url) : base(url) private AddressChangedHandler addressChanged;
private IBrowserSettings settings;
private TitleChangedHandler titleChanged;
private IText text;
event AddressChangedHandler IBrowserControl.AddressChanged
{ {
Dock = DockStyle.Fill; add { addressChanged += value; }
remove { addressChanged -= value; }
}
event TitleChangedHandler IBrowserControl.TitleChanged
{
add { titleChanged += value; }
remove { titleChanged -= value; }
}
public BrowserControl(IBrowserSettings settings, IText text) : base(settings.StartUrl)
{
this.settings = settings;
this.text = text;
Initialize();
}
public void NavigateBackwards()
{
GetBrowser().GoBack();
}
public void NavigateForwards()
{
GetBrowser().GoForward();
}
public void NavigateTo(string address)
{
if (!String.IsNullOrWhiteSpace(address) && Uri.IsWellFormedUriString(address, UriKind.RelativeOrAbsolute))
{
Load(address);
}
}
public void Reload()
{
GetBrowser().Reload();
}
private void Initialize()
{
AddressChanged += (o, args) => addressChanged?.Invoke(args.Address);
TitleChanged += (o, args) => titleChanged?.Invoke(args.Title);
MenuHandler = new BrowserContextMenuHandler(settings, text);
} }
} }
} }

View file

@ -67,6 +67,7 @@
<Compile Include="BrowserApplicationController.cs" /> <Compile Include="BrowserApplicationController.cs" />
<Compile Include="BrowserApplicationInfo.cs" /> <Compile Include="BrowserApplicationInfo.cs" />
<Compile Include="BrowserApplicationInstance.cs" /> <Compile Include="BrowserApplicationInstance.cs" />
<Compile Include="BrowserContextMenuHandler.cs" />
<Compile Include="BrowserControl.cs"> <Compile Include="BrowserControl.cs">
<SubType>Component</SubType> <SubType>Component</SubType>
</Compile> </Compile>

View file

@ -23,24 +23,26 @@ namespace SafeExamBrowser.Configuration.Settings
public bool AllowAddressBar => true; public bool AllowAddressBar => true;
public bool AllowBackwardNavigation => false; public bool AllowBackwardNavigation => true;
public bool AllowDebugConsole => true; public bool AllowDeveloperConsole => true;
public bool AllowForwardNavigation => false; public bool AllowForwardNavigation => true;
public bool AllowReloading => false; public bool AllowReloading => true;
public string CachePath public string CachePath
{ {
get { return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), settings.AppDataFolderName, "Cache"); } get { return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), settings.AppDataFolderName, "Cache"); }
} }
public bool FullScreenMode => throw new NotImplementedException(); public bool FullScreenMode => false;
public string LogFile public string LogFile
{ {
get { return Path.Combine(settings.LogFolderPath, $"{settings.RuntimeIdentifier}_Browser.txt"); } get { return Path.Combine(settings.LogFolderPath, $"{settings.RuntimeIdentifier}_Browser.txt"); }
} }
public string StartUrl => "www.duckduckgo.com";
} }
} }

View file

@ -12,6 +12,7 @@ using SafeExamBrowser.Contracts.UserInterface;
namespace SafeExamBrowser.Contracts.Configuration namespace SafeExamBrowser.Contracts.Configuration
{ {
public delegate void TerminationEventHandler(Guid id); public delegate void TerminationEventHandler(Guid id);
public delegate void NameChangedEventHandler(string name);
public interface IApplicationInstance public interface IApplicationInstance
{ {
@ -28,16 +29,16 @@ namespace SafeExamBrowser.Contracts.Configuration
/// <summary> /// <summary>
/// Event fired when the application instance has been terminated. /// Event fired when the application instance has been terminated.
/// </summary> /// </summary>
event TerminationEventHandler OnTerminated; event TerminationEventHandler Terminated;
/// <summary>
/// Event fired when the name or (document) title of the application instance has changed.
/// </summary>
event NameChangedEventHandler NameChanged;
/// <summary> /// <summary>
/// The main window of the application instance. /// The main window of the application instance.
/// </summary> /// </summary>
IWindow Window { get; } IWindow Window { get; }
/// <summary>
/// Registers the given window as the main window of the application instance.
/// </summary>
void RegisterWindow(IWindow window);
} }
} }

View file

@ -21,9 +21,9 @@ namespace SafeExamBrowser.Contracts.Configuration.Settings
bool AllowBackwardNavigation { get; } bool AllowBackwardNavigation { get; }
/// <summary> /// <summary>
/// Determines whether the user should be allowed to open the debug console of a browser window. /// Determines whether the user should be allowed to open the developer console of a browser window.
/// </summary> /// </summary>
bool AllowDebugConsole { get; } bool AllowDeveloperConsole { get; }
/// <summary> /// <summary>
/// Determines whether the user should be allowed to navigate forwards in a browser window. /// Determines whether the user should be allowed to navigate forwards in a browser window.
@ -49,5 +49,10 @@ namespace SafeExamBrowser.Contracts.Configuration.Settings
/// Determines whether the main browser window should be rendered in fullscreen mode, i.e. without window frame. /// Determines whether the main browser window should be rendered in fullscreen mode, i.e. without window frame.
/// </summary> /// </summary>
bool FullScreenMode { get; } bool FullScreenMode { get; }
/// <summary>
/// The start URL with which a new browser window should be loaded.
/// </summary>
string StartUrl { get; }
} }
} }

View file

@ -13,6 +13,7 @@ namespace SafeExamBrowser.Contracts.I18n
/// </summary> /// </summary>
public enum Key public enum Key
{ {
Browser_ShowDeveloperConsole,
MessageBox_ShutdownError, MessageBox_ShutdownError,
MessageBox_ShutdownErrorTitle, MessageBox_ShutdownErrorTitle,
MessageBox_SingleInstance, MessageBox_SingleInstance,

View file

@ -8,7 +8,39 @@
namespace SafeExamBrowser.Contracts.UserInterface namespace SafeExamBrowser.Contracts.UserInterface
{ {
public delegate void AddressChangedHandler(string address);
public delegate void TitleChangedHandler(string title);
public interface IBrowserControl public interface IBrowserControl
{ {
/// <summary>
/// Event fired when the address of the browser control changes.
/// </summary>
event AddressChangedHandler AddressChanged;
/// <summary>
/// Event fired when the current page (and thus the title) of the browser control changes.
/// </summary>
event TitleChangedHandler TitleChanged;
/// <summary>
/// Navigates to the previous page in the browser control history.
/// </summary>
void NavigateBackwards();
/// <summary>
/// Navigates to the next page in the browser control history.
/// </summary>
void NavigateForwards();
/// <summary>
/// Navigates to the specified web address.
/// </summary>
void NavigateTo(string address);
/// <summary>
/// Reloads the current web page.
/// </summary>
void Reload();
} }
} }

View file

@ -8,7 +8,43 @@
namespace SafeExamBrowser.Contracts.UserInterface namespace SafeExamBrowser.Contracts.UserInterface
{ {
public delegate void ActionRequestedHandler();
public interface IBrowserWindow : IWindow public interface IBrowserWindow : IWindow
{ {
/// <summary>
/// Event fired when the user changed the URL.
/// </summary>
event AddressChangedHandler AddressChanged;
/// <summary>
/// Event fired when the user would like to navigate backwards.
/// </summary>
event ActionRequestedHandler BackwardNavigationRequested;
/// <summary>
/// Event fired when the user would like to navigate forwards.
/// </summary>
event ActionRequestedHandler ForwardNavigationRequested;
/// <summary>
/// Event fired when the user would like to reload the current page.
/// </summary>
event ActionRequestedHandler ReloadRequested;
/// <summary>
/// Determines whether this window is the main browser window.
/// </summary>
bool IsMainWindow { get; set; }
/// <summary>
/// Updates the address bar of the browser window to the given value;
/// </summary>
void UpdateAddress(string adress);
/// <summary>
/// Sets the title of the browser window to the given value;
/// </summary>
void UpdateTitle(string title);
} }
} }

View file

@ -20,7 +20,7 @@ namespace SafeExamBrowser.Contracts.UserInterface
ITaskbarButton CreateApplicationButton(IApplicationInfo info); ITaskbarButton CreateApplicationButton(IApplicationInfo info);
/// <summary> /// <summary>
/// Creates a new browser window loaded with the given browser control. /// Creates a new browser window loaded with the given browser control and settings.
/// </summary> /// </summary>
IBrowserWindow CreateBrowserWindow(IBrowserControl control, IBrowserSettings settings); IBrowserWindow CreateBrowserWindow(IBrowserControl control, IBrowserSettings settings);

View file

@ -8,14 +8,14 @@
namespace SafeExamBrowser.Contracts.UserInterface namespace SafeExamBrowser.Contracts.UserInterface
{ {
public delegate void WindowCloseHandler(); public delegate void WindowClosingHandler();
public interface IWindow public interface IWindow
{ {
/// <summary> /// <summary>
/// Event fired when the window is closing. /// Event fired when the window is closing.
/// </summary> /// </summary>
event WindowCloseHandler OnClose; event WindowClosingHandler Closing;
/// <summary> /// <summary>
/// Brings the window to the foreground. /// Brings the window to the foreground.

View file

@ -1,24 +1,25 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<Text> <Text>
<MessageBox_ShutdownError>An unexpected error occurred during the shutdown procedure! Please consult the application log for more information...</MessageBox_ShutdownError> <Browser_ShowDeveloperConsole>Open Console</Browser_ShowDeveloperConsole>
<MessageBox_ShutdownErrorTitle>Shutdown Error</MessageBox_ShutdownErrorTitle> <MessageBox_ShutdownError>An unexpected error occurred during the shutdown procedure! Please consult the application log for more information...</MessageBox_ShutdownError>
<MessageBox_StartupError>An unexpected error occurred during the startup procedure! Please consult the application log for more information...</MessageBox_StartupError> <MessageBox_ShutdownErrorTitle>Shutdown Error</MessageBox_ShutdownErrorTitle>
<MessageBox_StartupErrorTitle>Startup Error</MessageBox_StartupErrorTitle> <MessageBox_StartupError>An unexpected error occurred during the startup procedure! Please consult the application log for more information...</MessageBox_StartupError>
<Notification_AboutTooltip>About Safe Exam Browser</Notification_AboutTooltip> <MessageBox_StartupErrorTitle>Startup Error</MessageBox_StartupErrorTitle>
<SplashScreen_InitializeBrowser>Initializing browser</SplashScreen_InitializeBrowser> <Notification_AboutTooltip>About Safe Exam Browser</Notification_AboutTooltip>
<SplashScreen_InitializeProcessMonitoring>Initializing process monitoring</SplashScreen_InitializeProcessMonitoring> <SplashScreen_InitializeBrowser>Initializing browser</SplashScreen_InitializeBrowser>
<SplashScreen_InitializeTaskbar>Initializing taskbar</SplashScreen_InitializeTaskbar> <SplashScreen_InitializeProcessMonitoring>Initializing process monitoring</SplashScreen_InitializeProcessMonitoring>
<SplashScreen_InitializeWindowMonitoring>Initializing window monitoring</SplashScreen_InitializeWindowMonitoring> <SplashScreen_InitializeTaskbar>Initializing taskbar</SplashScreen_InitializeTaskbar>
<SplashScreen_InitializeWorkingArea>Initializing working area</SplashScreen_InitializeWorkingArea> <SplashScreen_InitializeWindowMonitoring>Initializing window monitoring</SplashScreen_InitializeWindowMonitoring>
<SplashScreen_RestoreWorkingArea>Restoring working area</SplashScreen_RestoreWorkingArea> <SplashScreen_InitializeWorkingArea>Initializing working area</SplashScreen_InitializeWorkingArea>
<SplashScreen_ShutdownProcedure>Initiating shutdown procedure</SplashScreen_ShutdownProcedure> <SplashScreen_RestoreWorkingArea>Restoring working area</SplashScreen_RestoreWorkingArea>
<SplashScreen_StartEventHandling>Starting event handling</SplashScreen_StartEventHandling> <SplashScreen_ShutdownProcedure>Initiating shutdown procedure</SplashScreen_ShutdownProcedure>
<SplashScreen_StartupProcedure>Initiating startup procedure</SplashScreen_StartupProcedure> <SplashScreen_StartEventHandling>Starting event handling</SplashScreen_StartEventHandling>
<SplashScreen_StopEventHandling>Stopping event handling</SplashScreen_StopEventHandling> <SplashScreen_StartupProcedure>Initiating startup procedure</SplashScreen_StartupProcedure>
<SplashScreen_StopProcessMonitoring>Stopping process monitoring</SplashScreen_StopProcessMonitoring> <SplashScreen_StopEventHandling>Stopping event handling</SplashScreen_StopEventHandling>
<SplashScreen_StopWindowMonitoring>Stopping window monitoring</SplashScreen_StopWindowMonitoring> <SplashScreen_StopProcessMonitoring>Stopping process monitoring</SplashScreen_StopProcessMonitoring>
<SplashScreen_TerminateBrowser>Terminating browser</SplashScreen_TerminateBrowser> <SplashScreen_StopWindowMonitoring>Stopping window monitoring</SplashScreen_StopWindowMonitoring>
<SplashScreen_WaitExplorerStartup>Waiting for Windows explorer to start up</SplashScreen_WaitExplorerStartup> <SplashScreen_TerminateBrowser>Terminating browser</SplashScreen_TerminateBrowser>
<SplashScreen_WaitExplorerTermination>Waiting for Windows explorer to shut down</SplashScreen_WaitExplorerTermination> <SplashScreen_WaitExplorerStartup>Waiting for Windows explorer to start up</SplashScreen_WaitExplorerStartup>
<Version>Version</Version> <SplashScreen_WaitExplorerTermination>Waiting for Windows explorer to shut down</SplashScreen_WaitExplorerTermination>
<Version>Version</Version>
</Text> </Text>

View file

@ -5,7 +5,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface" xmlns:local="clr-namespace:SafeExamBrowser.UserInterface"
mc:Ignorable="d" mc:Ignorable="d"
Title="BrowserWindow" Height="500" Width="500" WindowState="Maximized"> Title="BrowserWindow" Height="500" Width="500" WindowState="Maximized" Icon=".\Images\Chromium.ico">
<Grid> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="30" /> <RowDefinition Height="30" />

View file

@ -7,6 +7,7 @@
*/ */
using System.Windows; using System.Windows;
using System.Windows.Controls;
using SafeExamBrowser.Contracts.Configuration.Settings; using SafeExamBrowser.Contracts.Configuration.Settings;
using SafeExamBrowser.Contracts.UserInterface; using SafeExamBrowser.Contracts.UserInterface;
@ -14,9 +15,33 @@ namespace SafeExamBrowser.UserInterface
{ {
public partial class BrowserWindow : Window, IBrowserWindow public partial class BrowserWindow : Window, IBrowserWindow
{ {
private bool isMainWindow;
private IBrowserSettings settings; private IBrowserSettings settings;
public WindowClosingHandler closing;
public event WindowCloseHandler OnClose; public bool IsMainWindow
{
get
{
return isMainWindow;
}
set
{
isMainWindow = value;
ApplySettings();
}
}
public event AddressChangedHandler AddressChanged;
public event ActionRequestedHandler BackwardNavigationRequested;
public event ActionRequestedHandler ForwardNavigationRequested;
public event ActionRequestedHandler ReloadRequested;
event WindowClosingHandler IWindow.Closing
{
add { closing += value; }
remove { closing -= value; }
}
public BrowserWindow(IBrowserControl browserControl, IBrowserSettings settings) public BrowserWindow(IBrowserControl browserControl, IBrowserSettings settings)
{ {
@ -36,6 +61,26 @@ namespace SafeExamBrowser.UserInterface
Activate(); Activate();
} }
public void UpdateAddress(string url)
{
Dispatcher.Invoke(() =>
{
UrlTextBox.TextChanged -= UrlTextBox_TextChanged;
UrlTextBox.Text = url;
UrlTextBox.TextChanged += UrlTextBox_TextChanged;
});
}
public void UpdateTitle(string title)
{
Dispatcher.Invoke(() => Title = title);
}
private void UrlTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
AddressChanged?.Invoke(UrlTextBox.Text);
}
private void InitializeBrowserWindow(IBrowserControl browserControl) private void InitializeBrowserWindow(IBrowserControl browserControl)
{ {
if (browserControl is System.Windows.Forms.Control) if (browserControl is System.Windows.Forms.Control)
@ -43,8 +88,26 @@ namespace SafeExamBrowser.UserInterface
BrowserControlHost.Child = browserControl as System.Windows.Forms.Control; BrowserControlHost.Child = browserControl as System.Windows.Forms.Control;
} }
Closing += (o, args) => closing?.Invoke();
UrlTextBox.TextChanged += UrlTextBox_TextChanged;
ReloadButton.Click += (o, args) => ReloadRequested?.Invoke();
BackButton.Click += (o, args) => BackwardNavigationRequested?.Invoke();
ForwardButton.Click += (o, args) => ForwardNavigationRequested?.Invoke();
ApplySettings();
}
private void ApplySettings()
{
if (IsMainWindow && settings.FullScreenMode)
{
MaxHeight = SystemParameters.WorkArea.Height;
ResizeMode = ResizeMode.NoResize;
WindowState = WindowState.Maximized;
WindowStyle = WindowStyle.None;
}
UrlTextBox.IsEnabled = settings.AllowAddressBar; UrlTextBox.IsEnabled = settings.AllowAddressBar;
UrlTextBox.Visibility = settings.AllowAddressBar ? Visibility.Visible : Visibility.Collapsed;
ReloadButton.IsEnabled = settings.AllowReloading; ReloadButton.IsEnabled = settings.AllowReloading;
ReloadButton.Visibility = settings.AllowReloading ? Visibility.Visible : Visibility.Collapsed; ReloadButton.Visibility = settings.AllowReloading ? Visibility.Visible : Visibility.Collapsed;
@ -54,8 +117,6 @@ namespace SafeExamBrowser.UserInterface
ForwardButton.IsEnabled = settings.AllowForwardNavigation; ForwardButton.IsEnabled = settings.AllowForwardNavigation;
ForwardButton.Visibility = settings.AllowForwardNavigation ? Visibility.Visible : Visibility.Collapsed; ForwardButton.Visibility = settings.AllowForwardNavigation ? Visibility.Visible : Visibility.Collapsed;
Closing += (o, args) => OnClose?.Invoke();
} }
} }
} }

View file

@ -37,7 +37,7 @@
</Button.Template> </Button.Template>
</Button> </Button>
<Grid Panel.ZIndex="10"> <Grid Panel.ZIndex="10">
<Rectangle x:Name="ActiveBar" Height="3" Width="40" VerticalAlignment="Bottom" Fill="LightSteelBlue" Visibility="Collapsed" /> <Rectangle x:Name="ActiveBar" Height="2" Width="40" VerticalAlignment="Bottom" Fill="LightSteelBlue" Visibility="Collapsed" />
</Grid> </Grid>
</Grid> </Grid>
</UserControl> </UserControl>

View file

@ -11,6 +11,7 @@ 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.Media;
using SafeExamBrowser.Contracts.Configuration; using SafeExamBrowser.Contracts.Configuration;
using SafeExamBrowser.Contracts.UserInterface; using SafeExamBrowser.Contracts.UserInterface;
using SafeExamBrowser.UserInterface.Utilities; using SafeExamBrowser.UserInterface.Utilities;
@ -37,7 +38,7 @@ namespace SafeExamBrowser.UserInterface.Controls
var instanceButton = new ApplicationInstanceButton(instance, info); var instanceButton = new ApplicationInstanceButton(instance, info);
instanceButton.Click += (id) => OnClick?.Invoke(id); instanceButton.Click += (id) => OnClick?.Invoke(id);
instance.OnTerminated += (id) => Instance_OnTerminated(id, instanceButton); instance.Terminated += (id) => Instance_OnTerminated(id, instanceButton);
instances.Add(instance); instances.Add(instance);
InstanceStackPanel.Children.Add(instanceButton); InstanceStackPanel.Children.Add(instanceButton);
@ -49,13 +50,24 @@ namespace SafeExamBrowser.UserInterface.Controls
{ {
Button.ToolTip = info.Tooltip; Button.ToolTip = info.Tooltip;
Button.Content = IconResourceLoader.Load(info.IconResource); Button.Content = IconResourceLoader.Load(info.IconResource);
Button.MouseEnter += (o, args) => InstancePopup.IsOpen = instances.Count > 1; Button.MouseEnter += (o, args) => InstancePopup.IsOpen = instances.Count > 1;
Button.MouseLeave += (o, args) => InstancePopup.IsOpen &= InstancePopup.IsMouseOver || ActiveBar.IsMouseOver; Button.MouseLeave += (o, args) => InstancePopup.IsOpen &= InstancePopup.IsMouseOver || ActiveBar.IsMouseOver;
ActiveBar.MouseLeave += (o, args) => InstancePopup.IsOpen &= InstancePopup.IsMouseOver || Button.IsMouseOver; ActiveBar.MouseLeave += (o, args) => InstancePopup.IsOpen &= InstancePopup.IsMouseOver || Button.IsMouseOver;
InstancePopup.MouseLeave += (o, args) => InstancePopup.IsOpen = false; InstancePopup.MouseLeave += (o, args) => InstancePopup.IsOpen = false;
InstancePopup.Opened += (o, args) => ActiveBar.Width = Double.NaN;
InstancePopup.Closed += (o, args) => ActiveBar.Width = 40; InstancePopup.Opened += (o, args) =>
{
ActiveBar.Width = Double.NaN;
Background = (Brush) new BrushConverter().ConvertFrom("#2AFFFFFF");
};
InstancePopup.Closed += (o, args) =>
{
ActiveBar.Width = 40;
Background = (Brush) new BrushConverter().ConvertFrom("#00000000");
};
InstanceStackPanel.SizeChanged += (o, args) => InstanceStackPanel.SizeChanged += (o, args) =>
{ {
if (instances.Count > 9) if (instances.Count > 9)

View file

@ -10,7 +10,7 @@
<Button.Template> <Button.Template>
<ControlTemplate TargetType="Button"> <ControlTemplate TargetType="Button">
<Border x:Name="ButtonContent" Background="#00000000" Padding="5"> <Border x:Name="ButtonContent" Background="#00000000" Padding="5">
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" ContentSource="Content" /> <ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Left" ContentSource="Content" />
</Border> </Border>
<ControlTemplate.Triggers> <ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True"> <Trigger Property="IsMouseOver" Value="True">

View file

@ -36,7 +36,16 @@ namespace SafeExamBrowser.UserInterface.Controls
{ {
Icon.Content = IconResourceLoader.Load(info.IconResource); Icon.Content = IconResourceLoader.Load(info.IconResource);
Text.Text = instance.Name; Text.Text = instance.Name;
Button.ToolTip = $"{instance.Name} - {info.Name}"; Button.ToolTip = instance.Name;
instance.NameChanged += (name) =>
{
Dispatcher.Invoke(() =>
{
Text.Text = name;
Button.ToolTip = name;
});
};
} }
private void Button_Click(object sender, RoutedEventArgs e) private void Button_Click(object sender, RoutedEventArgs e)

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

View file

@ -163,5 +163,8 @@
<ItemGroup> <ItemGroup>
<Resource Include="Images\SafeExamBrowser.ico" /> <Resource Include="Images\SafeExamBrowser.ico" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Resource Include="Images\Chromium.ico" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project> </Project>

View file

@ -63,10 +63,11 @@ namespace SafeExamBrowser
text = new Text(textResource); text = new Text(textResource);
aboutInfo = new AboutNotificationInfo(text); aboutInfo = new AboutNotificationInfo(text);
browserController = new BrowserApplicationController(settings, uiFactory); browserController = new BrowserApplicationController(settings, text, uiFactory);
processMonitor = new ProcessMonitor(new ModuleLogger(logger, typeof(ProcessMonitor)), nativeMethods); processMonitor = new ProcessMonitor(new ModuleLogger(logger, typeof(ProcessMonitor)), nativeMethods);
windowMonitor = new WindowMonitor(new ModuleLogger(logger, typeof(WindowMonitor)), nativeMethods); windowMonitor = new WindowMonitor(new ModuleLogger(logger, typeof(WindowMonitor)), nativeMethods);
workingArea = new WorkingArea(new ModuleLogger(logger, typeof(WorkingArea)), nativeMethods); workingArea = new WorkingArea(new ModuleLogger(logger, typeof(WorkingArea)), nativeMethods);
eventController = new EventController(new ModuleLogger(logger, typeof(EventController)), processMonitor, Taskbar, windowMonitor, workingArea); eventController = new EventController(new ModuleLogger(logger, typeof(EventController)), processMonitor, Taskbar, windowMonitor, workingArea);
ShutdownController = new ShutdownController(logger, settings, text, uiFactory); ShutdownController = new ShutdownController(logger, settings, text, uiFactory);
StartupController = new StartupController(logger, settings, text, uiFactory); StartupController = new StartupController(logger, settings, text, uiFactory);