Index: Core/Common/src/Core.Common.Gui/Commands/OpenProjectCommand.cs
===================================================================
diff -u
--- Core/Common/src/Core.Common.Gui/Commands/OpenProjectCommand.cs (revision 0)
+++ Core/Common/src/Core.Common.Gui/Commands/OpenProjectCommand.cs (revision 173fe221a98b3d8dfb9e0aeee0d93504ad899730)
@@ -0,0 +1,106 @@
+using System;
+using System.IO;
+
+using Core.Common.Base.Data;
+using Core.Common.Base.Storage;
+using Core.Common.Gui.Properties;
+
+using log4net;
+
+namespace Core.Common.Gui.Commands
+{
+ ///
+ /// Opens an existing project file from hard disk and loads that into the application.
+ ///
+ public class OpenProjectCommand : IGuiCommand
+ {
+ private static readonly ILog Log = LogManager.GetLogger(typeof(GuiCommandHandler));
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public OpenProjectCommand()
+ {
+ Enabled = true;
+ Checked = false;
+ }
+
+ ///
+ /// Gets a value indicating whether a has successfully been loaded.
+ ///
+ public bool LoadWasSuccesful { get; private set; }
+
+ public bool Enabled { get; private set; }
+ public bool Checked { get; private set; }
+
+ public IGui Gui { get; set; }
+
+ ///
+ /// Start the operation of opening a specified project file.
+ ///
+ /// The file path of the project to open.
+ public void Execute(string filePath)
+ {
+ Execute(new object[]
+ {
+ filePath
+ });
+ }
+
+ public void Execute(params object[] arguments)
+ {
+ LoadWasSuccesful = false;
+ Log.Info(Resources.Project_existing_opening_project);
+
+ var filePath = (string)arguments[0];
+ Project loadedProject = TryReadProjectFromPath(filePath);
+ if (loadedProject == null)
+ {
+ Log.Warn(Resources.Project_existing_project_opening_failed);
+ return;
+ }
+
+ // Project loaded successfully, close current project
+ if (Gui.Project != null)
+ {
+ // remove views before closing project.
+ Gui.CommandHandler.RemoveAllViewsForItem(Gui.Project);
+ }
+
+ Gui.ProjectFilePath = filePath;
+ Gui.Project = loadedProject;
+ Gui.Project.Name = Path.GetFileNameWithoutExtension(filePath);
+
+ // Set the gui selection to the current project
+ Gui.Selection = Gui.Project;
+
+ // Update the window title
+ Gui.UpdateTitle();
+
+ LoadWasSuccesful = true;
+ Log.Info(Resources.Project_existing_successfully_opened);
+ }
+
+ private Project TryReadProjectFromPath(string filePath)
+ {
+ IStoreProject storage = Gui.Storage;
+ try
+ {
+ return storage.LoadProject(filePath);
+ }
+ catch (ArgumentException e)
+ {
+ Log.Warn(e.Message);
+ }
+ catch (CouldNotConnectException e)
+ {
+ Log.Warn(e.Message);
+ }
+ catch (StorageValidationException e)
+ {
+ Log.Warn(e.Message);
+ }
+ return null;
+ }
+ }
+}
\ No newline at end of file
Index: Core/Common/src/Core.Common.Gui/Core.Common.Gui.csproj
===================================================================
diff -u -r30b1d22e83a751ea0ac8a5924db199b67c36a623 -r173fe221a98b3d8dfb9e0aeee0d93504ad899730
--- Core/Common/src/Core.Common.Gui/Core.Common.Gui.csproj (.../Core.Common.Gui.csproj) (revision 30b1d22e83a751ea0ac8a5924db199b67c36a623)
+++ Core/Common/src/Core.Common.Gui/Core.Common.Gui.csproj (.../Core.Common.Gui.csproj) (revision 173fe221a98b3d8dfb9e0aeee0d93504ad899730)
@@ -120,6 +120,7 @@
+
Form
Index: Core/Common/src/Core.Common.Gui/Forms/MainWindow/MainWindow.xaml.cs
===================================================================
diff -u -r30b1d22e83a751ea0ac8a5924db199b67c36a623 -r173fe221a98b3d8dfb9e0aeee0d93504ad899730
--- Core/Common/src/Core.Common.Gui/Forms/MainWindow/MainWindow.xaml.cs (.../MainWindow.xaml.cs) (revision 30b1d22e83a751ea0ac8a5924db199b67c36a623)
+++ Core/Common/src/Core.Common.Gui/Forms/MainWindow/MainWindow.xaml.cs (.../MainWindow.xaml.cs) (revision 173fe221a98b3d8dfb9e0aeee0d93504ad899730)
@@ -63,6 +63,7 @@
private IEnumerable ribbonCommandHandlers;
private readonly CreateNewProjectCommand newProjectCommand;
+ private readonly OpenProjectCommand openProjectCommand;
///
/// This is used when user selects non-contextual tab explicitly. Then we won't activate contextual tab on the next view activation.
@@ -85,6 +86,7 @@
windowInteropHelper = new WindowInteropHelper(this);
newProjectCommand = new CreateNewProjectCommand { Gui = gui };
+ openProjectCommand = new OpenProjectCommand { Gui = gui };
log.Info(Properties.Resources.MainWindow_MainWindow_Main_window_created_);
}
@@ -536,7 +538,7 @@
{
try
{
- Gui.CommandHandler.OpenExistingProject(path);
+ openProjectCommand.Execute(path);
RecentProjectsTabControl.Items.Remove(newItem);
RecentProjectsTabControl.Items.Insert(1, newItem);
}
Index: Core/Common/src/Core.Common.Gui/GuiCommandHandler.cs
===================================================================
diff -u -r30b1d22e83a751ea0ac8a5924db199b67c36a623 -r173fe221a98b3d8dfb9e0aeee0d93504ad899730
--- Core/Common/src/Core.Common.Gui/GuiCommandHandler.cs (.../GuiCommandHandler.cs) (revision 30b1d22e83a751ea0ac8a5924db199b67c36a623)
+++ Core/Common/src/Core.Common.Gui/GuiCommandHandler.cs (.../GuiCommandHandler.cs) (revision 173fe221a98b3d8dfb9e0aeee0d93504ad899730)
@@ -68,7 +68,7 @@
///
/// Location of the storage file.
/// true if an existing has been loaded, false otherwise.
- public bool OpenExistingProject(string filePath)
+ private bool OpenExistingProject(string filePath)
{
Log.Info(Resources.Project_existing_opening_project);
Index: Core/Common/src/Core.Common.Gui/IGuiCommandHandler.cs
===================================================================
diff -u -r30b1d22e83a751ea0ac8a5924db199b67c36a623 -r173fe221a98b3d8dfb9e0aeee0d93504ad899730
--- Core/Common/src/Core.Common.Gui/IGuiCommandHandler.cs (.../IGuiCommandHandler.cs) (revision 30b1d22e83a751ea0ac8a5924db199b67c36a623)
+++ Core/Common/src/Core.Common.Gui/IGuiCommandHandler.cs (.../IGuiCommandHandler.cs) (revision 173fe221a98b3d8dfb9e0aeee0d93504ad899730)
@@ -25,16 +25,6 @@
bool OpenExistingProject();
///
- /// Opens an existing project from file.
- ///
- /// The path to the existing project file.
- ///
- /// The opening action might be cancelled (due to user interaction).
- ///
- /// Whether or not an existing project was correctly opened.
- bool OpenExistingProject(string filePath);
-
- ///
/// Closes the current project.
///
void CloseProject();
Index: Core/Common/test/Core.Common.Gui.Test/Commands/OpenProjectCommandTest.cs
===================================================================
diff -u
--- Core/Common/test/Core.Common.Gui.Test/Commands/OpenProjectCommandTest.cs (revision 0)
+++ Core/Common/test/Core.Common.Gui.Test/Commands/OpenProjectCommandTest.cs (revision 173fe221a98b3d8dfb9e0aeee0d93504ad899730)
@@ -0,0 +1,179 @@
+using System;
+
+using Core.Common.Base.Data;
+using Core.Common.Base.Storage;
+using Core.Common.Gui.Commands;
+using Core.Common.TestUtil;
+
+using NUnit.Framework;
+
+using Rhino.Mocks;
+
+namespace Core.Common.Gui.Test.Commands
+{
+ [TestFixture]
+ public class OpenProjectCommandTest
+ {
+ [Test]
+ public void DefaultConstructor_ExpectedValues()
+ {
+ // Call
+ var command = new OpenProjectCommand();
+
+ // Assert
+ Assert.IsInstanceOf(command);
+ Assert.IsTrue(command.Enabled);
+ Assert.IsFalse(command.Checked);
+ Assert.IsFalse(command.LoadWasSuccesful);
+ Assert.IsNull(command.Gui);
+ }
+
+ [Test]
+ public void Execute_ValidFilePath_SetProjectAndReturnLoadWasSuccesfulTrue()
+ {
+ // Setup
+ var expectedProject = new Project();
+ const string path = "cool file.bro";
+
+ var mocks = new MockRepository();
+ var storageMock = mocks.StrictMock();
+ storageMock.Expect(s => s.LoadProject(path)).Return(expectedProject);
+
+ var guiMock = mocks.Stub();
+ guiMock.Project = null;
+ guiMock.Stub(g => g.Storage).Return(storageMock);
+ guiMock.Expect(g => g.UpdateTitle());
+ mocks.ReplayAll();
+
+ var command = new OpenProjectCommand
+ {
+ Gui = guiMock
+ };
+
+ // Call
+ Action call = () => command.Execute(path);
+
+ // Assert
+ var expectedMessages = new[]
+ {
+ "Openen van bestaand Ringtoets project.",
+ "Bestaand Ringtoets project succesvol geopend."
+ };
+ TestHelper.AssertLogMessagesAreGenerated(call, expectedMessages, 2);
+ Assert.AreSame(expectedProject, guiMock.Project);
+ Assert.AreEqual("cool file", expectedProject.Name);
+ Assert.AreEqual(path, guiMock.ProjectFilePath);
+ Assert.AreSame(expectedProject, guiMock.Selection);
+ Assert.True(command.LoadWasSuccesful);
+ }
+
+ [Test]
+ public void Execute_ValidFilePathAndAlreadyHasProject_CloseViewsOldProjectAndSetProjectAndReturnLoadWasSuccesfulTrue()
+ {
+ // Setup
+ var originalProject = new Project();
+ var expectedProject = new Project();
+ const string path = "cool file.bro";
+
+ var mocks = new MockRepository();
+ var storageMock = mocks.StrictMock();
+ storageMock.Expect(s => s.LoadProject(path)).Return(expectedProject);
+
+ var commandHandlerMock = mocks.StrictMock();
+ commandHandlerMock.Expect(ch => ch.RemoveAllViewsForItem(originalProject));
+
+ var guiMock = mocks.Stub();
+ guiMock.Project = originalProject;
+ guiMock.Stub(g => g.Storage).Return(storageMock);
+ guiMock.Expect(g => g.UpdateTitle());
+ guiMock.CommandHandler = commandHandlerMock;
+ mocks.ReplayAll();
+
+ var command = new OpenProjectCommand
+ {
+ Gui = guiMock
+ };
+
+ // Call
+ command.Execute(path);
+
+ // Assert
+ Assert.AreSame(expectedProject, guiMock.Project);
+ Assert.AreEqual("cool file", expectedProject.Name);
+ Assert.AreEqual(path, guiMock.ProjectFilePath);
+ Assert.AreSame(expectedProject, guiMock.Selection);
+ Assert.True(command.LoadWasSuccesful);
+ }
+
+ [Test]
+ public void Execute_StorageThrowsArgumentException_DoNotAffectProjectAndViewAndLogError()
+ {
+ ExecuteOpenProjectCommandAndThrowExceptionDuringLoad(new ArgumentException(""));
+ }
+
+ [Test]
+ public void Execute_StorageThrowsCouldNotConnectException_DoNotAffectProjectAndViewAndLogError()
+ {
+ ExecuteOpenProjectCommandAndThrowExceptionDuringLoad(new CouldNotConnectException(""));
+ }
+
+ [Test]
+ public void Execute_StorageThrowsStorageValidationException_DoNotAffectProjectAndViewAndLogError()
+ {
+ ExecuteOpenProjectCommandAndThrowExceptionDuringLoad(new StorageValidationException(""));
+ }
+
+ private static void ExecuteOpenProjectCommandAndThrowExceptionDuringLoad(Exception exception)
+ {
+ // Setup
+ const string originalName = "original name";
+ const string originalPath = originalName + ".tof";
+
+ var originalProject = new Project
+ {
+ Name = originalName
+ };
+ const string path = "cool file.bro";
+ string errorMessage = exception.Message;
+
+ var mocks = new MockRepository();
+ var storageMock = mocks.StrictMock();
+ storageMock.Expect(s => s.LoadProject(path)).Throw(exception);
+
+ var commandHandlerMock = mocks.StrictMock();
+ commandHandlerMock.Expect(ch => ch.RemoveAllViewsForItem(originalProject));
+
+ var guiMock = mocks.Stub();
+ guiMock.Project = originalProject;
+ guiMock.Stub(g => g.Storage).Return(storageMock);
+ guiMock.Expect(g => g.UpdateTitle());
+ guiMock.CommandHandler = commandHandlerMock;
+ guiMock.ProjectFilePath = originalPath;
+ mocks.ReplayAll();
+
+ var command = new OpenProjectCommand
+ {
+ Gui = guiMock
+ };
+
+ // Call
+ Action call = () => command.Execute(path);
+
+ // Assert
+ var expectedMessages = new[]
+ {
+ "Openen van bestaand Ringtoets project.",
+ errorMessage,
+ "Het is niet gelukt om het Ringtoets project te laden."
+ };
+ TestHelper.AssertLogMessagesAreGenerated(call, expectedMessages, 3);
+ Assert.AreSame(originalProject, guiMock.Project,
+ "Original project should still exist.");
+ Assert.AreEqual(originalName, originalProject.Name,
+ "Name should not be updated");
+ Assert.AreEqual(originalPath, guiMock.ProjectFilePath,
+ "Project file path should remain unchanged.");
+ Assert.False(command.LoadWasSuccesful);
+ }
+ }
+}
\ No newline at end of file
Index: Core/Common/test/Core.Common.Gui.Test/Core.Common.Gui.Test.csproj
===================================================================
diff -u -r30b1d22e83a751ea0ac8a5924db199b67c36a623 -r173fe221a98b3d8dfb9e0aeee0d93504ad899730
--- Core/Common/test/Core.Common.Gui.Test/Core.Common.Gui.Test.csproj (.../Core.Common.Gui.Test.csproj) (revision 30b1d22e83a751ea0ac8a5924db199b67c36a623)
+++ Core/Common/test/Core.Common.Gui.Test/Core.Common.Gui.Test.csproj (.../Core.Common.Gui.Test.csproj) (revision 173fe221a98b3d8dfb9e0aeee0d93504ad899730)
@@ -57,6 +57,7 @@
+