Continued implementing the scaffolding:
- Added composition root - Implemented XML resource for I18n
This commit is contained in:
parent
936f72c8bd
commit
0e9571fe10
12 changed files with 165 additions and 23 deletions
|
@ -13,21 +13,34 @@ using SafeExamBrowser.Core.I18n;
|
||||||
namespace SafeExamBrowser.Core.UnitTests
|
namespace SafeExamBrowser.Core.UnitTests
|
||||||
{
|
{
|
||||||
[TestClass]
|
[TestClass]
|
||||||
public class StringsTests
|
public class TextTests
|
||||||
{
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void MustNeverBeNull()
|
||||||
|
{
|
||||||
|
Assert.IsNotNull(Text.Instance);
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void MustNeverReturnNull()
|
public void MustNeverReturnNull()
|
||||||
{
|
{
|
||||||
var text = Strings.Get((Key) (-1));
|
var text = Text.Instance.Get((Key) (-1));
|
||||||
|
|
||||||
Assert.IsNotNull(text);
|
Assert.IsNotNull(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[ExpectedException(typeof(ArgumentNullException))]
|
||||||
|
public void MustNotAllowBeingNull()
|
||||||
|
{
|
||||||
|
Text.Instance = null;
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
[ExpectedException(typeof(ArgumentNullException))]
|
[ExpectedException(typeof(ArgumentNullException))]
|
||||||
public void MustNotAllowNullResource()
|
public void MustNotAllowNullResource()
|
||||||
{
|
{
|
||||||
Strings.Initialize(null);
|
new Text(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -48,7 +48,7 @@
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="I18n\StringsTests.cs" />
|
<Compile Include="I18n\TextTests.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -11,8 +11,8 @@ using SafeExamBrowser.Core.I18n;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Core.Contracts
|
namespace SafeExamBrowser.Core.Contracts
|
||||||
{
|
{
|
||||||
public interface IStringResource
|
public interface ITextResource
|
||||||
{
|
{
|
||||||
IDictionary<Key, string> LoadStrings();
|
IDictionary<Key, string> LoadText();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -10,6 +10,7 @@ namespace SafeExamBrowser.Core.I18n
|
||||||
{
|
{
|
||||||
public enum Key
|
public enum Key
|
||||||
{
|
{
|
||||||
|
MessageBox_FatalErrorTitle,
|
||||||
MessageBox_SingleInstance,
|
MessageBox_SingleInstance,
|
||||||
MessageBox_SingleInstanceTitle
|
MessageBox_SingleInstanceTitle
|
||||||
}
|
}
|
||||||
|
|
21
SafeExamBrowser.Core/I18n/NullTextResource.cs
Normal file
21
SafeExamBrowser.Core/I18n/NullTextResource.cs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* 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 System.Collections.Generic;
|
||||||
|
using SafeExamBrowser.Core.Contracts;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Core.I18n
|
||||||
|
{
|
||||||
|
class NullTextResource : ITextResource
|
||||||
|
{
|
||||||
|
public IDictionary<Key, string> LoadText()
|
||||||
|
{
|
||||||
|
return new Dictionary<Key, string>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,21 +12,42 @@ using SafeExamBrowser.Core.Contracts;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Core.I18n
|
namespace SafeExamBrowser.Core.I18n
|
||||||
{
|
{
|
||||||
public static class Strings
|
public class Text
|
||||||
{
|
{
|
||||||
private static IDictionary<Key, string> cache = new Dictionary<Key, string>();
|
private static Text instance;
|
||||||
|
private static readonly object @lock = new object();
|
||||||
|
|
||||||
public static void Initialize(IStringResource resource)
|
private IDictionary<Key, string> cache = new Dictionary<Key, string>();
|
||||||
|
|
||||||
|
public Text(ITextResource resource)
|
||||||
{
|
{
|
||||||
if (resource == null)
|
if (resource == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(resource));
|
throw new ArgumentNullException(nameof(resource));
|
||||||
}
|
}
|
||||||
|
|
||||||
cache = resource.LoadStrings();
|
cache = resource.LoadText();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string Get(Key key)
|
public static Text Instance
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (@lock)
|
||||||
|
{
|
||||||
|
return instance ?? new Text(new NullTextResource());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
lock (@lock)
|
||||||
|
{
|
||||||
|
instance = value ?? throw new ArgumentNullException(nameof(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Get(Key key)
|
||||||
{
|
{
|
||||||
return cache.ContainsKey(key) ? cache[key] : $"Could not find string for key '{key}'!";
|
return cache.ContainsKey(key) ? cache[key] : $"Could not find string for key '{key}'!";
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8" ?>
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
<Text>
|
<Text>
|
||||||
|
<MessageBox_FatalErrorTitle>Fatal Error</MessageBox_FatalErrorTitle>
|
||||||
<MessageBox_SingleInstance>You can only run one instance of SEB at a time.</MessageBox_SingleInstance>
|
<MessageBox_SingleInstance>You can only run one instance of SEB at a time.</MessageBox_SingleInstance>
|
||||||
<MessageBox_SingleInstanceTitle>Startup Not Allowed</MessageBox_SingleInstanceTitle>
|
<MessageBox_SingleInstanceTitle>Startup Not Allowed</MessageBox_SingleInstanceTitle>
|
||||||
</Text>
|
</Text>
|
38
SafeExamBrowser.Core/I18n/XmlTextResource.cs
Normal file
38
SafeExamBrowser.Core/I18n/XmlTextResource.cs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* 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 System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
using SafeExamBrowser.Core.Contracts;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Core.I18n
|
||||||
|
{
|
||||||
|
public class XmlTextResource : ITextResource
|
||||||
|
{
|
||||||
|
public IDictionary<Key, string> LoadText()
|
||||||
|
{
|
||||||
|
var assembly = Assembly.GetAssembly(typeof(XmlTextResource)).Location;
|
||||||
|
var path = Path.GetDirectoryName(assembly) + $@"\{nameof(I18n)}\Text.xml";
|
||||||
|
var xml = XDocument.Load(path);
|
||||||
|
var text = new Dictionary<Key, string>();
|
||||||
|
|
||||||
|
foreach (var definition in xml.Root.Descendants())
|
||||||
|
{
|
||||||
|
if (Enum.TryParse(definition.Name.LocalName, out Key key))
|
||||||
|
{
|
||||||
|
text[key] = definition.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,14 +40,18 @@
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Contracts\IStringResource.cs" />
|
<Compile Include="Contracts\ITextResource.cs" />
|
||||||
<Compile Include="Contracts\ITaskbar.cs" />
|
<Compile Include="Contracts\ITaskbar.cs" />
|
||||||
<Compile Include="I18n\Key.cs" />
|
<Compile Include="I18n\Key.cs" />
|
||||||
<Compile Include="I18n\Strings.cs" />
|
<Compile Include="I18n\NullTextResource.cs" />
|
||||||
|
<Compile Include="I18n\Text.cs" />
|
||||||
|
<Compile Include="I18n\XmlTextResource.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="I18n\Text.xml" />
|
<Content Include="I18n\Text.xml">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
</Project>
|
</Project>
|
|
@ -10,7 +10,6 @@ using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using SafeExamBrowser.Core.I18n;
|
using SafeExamBrowser.Core.I18n;
|
||||||
using SafeExamBrowser.UserInterface;
|
|
||||||
|
|
||||||
namespace SafeExamBrowser
|
namespace SafeExamBrowser
|
||||||
{
|
{
|
||||||
|
@ -21,22 +20,36 @@ namespace SafeExamBrowser
|
||||||
[STAThread]
|
[STAThread]
|
||||||
public static void Main()
|
public static void Main()
|
||||||
{
|
{
|
||||||
if (mutex.WaitOne(TimeSpan.Zero, true))
|
try
|
||||||
{
|
{
|
||||||
StartApplication();
|
var compositionRoot = new CompositionRoot();
|
||||||
|
|
||||||
|
compositionRoot.InitializeGlobalModules();
|
||||||
|
compositionRoot.BuildObjectGraph();
|
||||||
|
|
||||||
|
StartApplication(compositionRoot.Taskbar);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MessageBox.Show(e.Message + "\n\n" + e.StackTrace, Text.Instance.Get(Key.MessageBox_FatalErrorTitle));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void StartApplication(Window taskbar)
|
||||||
|
{
|
||||||
|
if (NoInstanceRunning())
|
||||||
|
{
|
||||||
|
new App().Run(taskbar);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MessageBox.Show(Strings.Get(Key.MessageBox_SingleInstance), Strings.Get(Key.MessageBox_SingleInstanceTitle));
|
MessageBox.Show(Text.Instance.Get(Key.MessageBox_SingleInstance), Text.Instance.Get(Key.MessageBox_SingleInstanceTitle));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void StartApplication()
|
private static bool NoInstanceRunning()
|
||||||
{
|
{
|
||||||
var app = new App();
|
return mutex.WaitOne(TimeSpan.Zero, true);
|
||||||
var taskbar = new Taskbar();
|
|
||||||
|
|
||||||
app.Run(taskbar);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
29
SafeExamBrowser/CompositionRoot.cs
Normal file
29
SafeExamBrowser/CompositionRoot.cs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* 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 System.Windows;
|
||||||
|
using SafeExamBrowser.Core.I18n;
|
||||||
|
using SafeExamBrowser.UserInterface;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser
|
||||||
|
{
|
||||||
|
class CompositionRoot
|
||||||
|
{
|
||||||
|
public Window Taskbar { get; private set; }
|
||||||
|
|
||||||
|
public void InitializeGlobalModules()
|
||||||
|
{
|
||||||
|
Text.Instance = new Text(new XmlTextResource());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void BuildObjectGraph()
|
||||||
|
{
|
||||||
|
Taskbar = new Taskbar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -51,6 +51,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="App.cs" />
|
<Compile Include="App.cs" />
|
||||||
|
<Compile Include="CompositionRoot.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs">
|
<Compile Include="Properties\AssemblyInfo.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
|
Loading…
Reference in a new issue