Index: Ringtoets/Common/src/Ringtoets.Common.Forms/Ringtoets.Common.Forms.csproj =================================================================== diff -u -rb47c41dd3741ada477388e6c8a9224ecb66291e7 -r36b6f1f7c1ddf585689512eb61256d41a1e0ca64 --- Ringtoets/Common/src/Ringtoets.Common.Forms/Ringtoets.Common.Forms.csproj (.../Ringtoets.Common.Forms.csproj) (revision b47c41dd3741ada477388e6c8a9224ecb66291e7) +++ Ringtoets/Common/src/Ringtoets.Common.Forms/Ringtoets.Common.Forms.csproj (.../Ringtoets.Common.Forms.csproj) (revision 36b6f1f7c1ddf585689512eb61256d41a1e0ca64) @@ -61,8 +61,8 @@ True Resources.resx - - + + UserControl Fisheye: Tag 36b6f1f7c1ddf585689512eb61256d41a1e0ca64 refers to a dead (removed) revision in file `Ringtoets/Common/src/Ringtoets.Common.Forms/TreeNodeInfos/CalculationTreeNodeInfoFactory.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 36b6f1f7c1ddf585689512eb61256d41a1e0ca64 refers to a dead (removed) revision in file `Ringtoets/Common/src/Ringtoets.Common.Forms/TreeNodeInfos/ContextMenuItemFactory.cs'. Fisheye: No comparison available. Pass `N' to diff? Index: Ringtoets/Common/src/Ringtoets.Common.Forms/TreeNodeInfos/RingtoetsContextMenuItemFactory.cs =================================================================== diff -u --- Ringtoets/Common/src/Ringtoets.Common.Forms/TreeNodeInfos/RingtoetsContextMenuItemFactory.cs (revision 0) +++ Ringtoets/Common/src/Ringtoets.Common.Forms/TreeNodeInfos/RingtoetsContextMenuItemFactory.cs (revision 36b6f1f7c1ddf585689512eb61256d41a1e0ca64) @@ -0,0 +1,218 @@ +// Copyright (C) Stichting Deltares 2016. All rights reserved. +// +// This file is part of Ringtoets. +// +// Ringtoets is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Linq; +using System.Windows.Forms; +using Core.Common.Gui.ContextMenu; +using Ringtoets.Common.Data.Calculation; +using Ringtoets.Common.Data.FailureMechanism; +using Ringtoets.Common.Forms.Helpers; +using Ringtoets.Common.Forms.PresentationObjects; +using Ringtoets.Common.Forms.Properties; +using RingtoetsCommonDataResources = Ringtoets.Common.Data.Properties.Resources; +using BaseResources = Core.Common.Base.Properties.Resources; + +namespace Ringtoets.Common.Forms.TreeNodeInfos +{ + /// + /// This class represents a factory for creating . + /// + public static class RingtoetsContextMenuItemFactory + { + /// + /// This method adds a context menu item for creating new calculation groups. + /// + /// The builder to add the context menu item to. + /// The calculation group involved. + public static void AddCreateCalculationGroupItem(IContextMenuBuilder builder, CalculationGroup calculationGroup) + { + var createCalculationGroupItem = new StrictContextMenuItem( + Resources.CalculationGroup_Add_CalculationGroup, + Resources.CalculationGroup_Add_CalculationGroup_Tooltip, + Resources.AddFolderIcon, + (o, args) => CreateCalculationGroup(calculationGroup)); + + builder.AddCustomItem(createCalculationGroupItem); + } + + /// + /// This method adds a context menu item for creating new calculations. + /// + /// The builder to add the context menu item to. + /// The calculation group context involved. + /// The action for adding a calculation to the calculation group. + public static void AddCreateCalculationItem(IContextMenuBuilder builder, TCalculationGroupContext calculationGroupContext, Action addCalculation) + where TCalculationGroupContext : ICalculationContext + { + var createCalculationItem = new StrictContextMenuItem( + Resources.CalculationGroup_Add_Calculation, + Resources.CalculationGroup_Add_Calculation_Tooltip, + Resources.FailureMechanismIcon, + (o, args) => addCalculation(calculationGroupContext)); + + builder.AddCustomItem(createCalculationItem); + } + + /// + /// This method adds a context menu item for clearing the output of all calculations in the calculation group. + /// + /// The builder to add the context menu item to. + /// The calculation group involved. + public static void AddClearAllCalculationOutputInGroupItem(IContextMenuBuilder builder, CalculationGroup calculationGroup) + { + var clearAllItem = new StrictContextMenuItem( + Resources.Clear_all_output, + Resources.CalculationGroup_ClearOutput_ToolTip, + Resources.ClearIcon, + (o, args) => ClearAllCalculationOutputInGroup(calculationGroup)); + + if (!calculationGroup.HasOutput()) + { + clearAllItem.Enabled = false; + clearAllItem.ToolTipText = Resources.CalculationGroup_ClearOutput_No_calculation_with_output_to_clear; + } + + builder.AddCustomItem(clearAllItem); + } + + /// + /// This method adds a context menu item for performing all calculations in the calculation group. + /// + /// The builder to add the context menu item to. + /// The calculation group involved. + /// The calculation group context belonging to the calculation group. + /// The action that performs all calculations. + public static void AddPerformAllCalculationsInGroupItem + (IContextMenuBuilder builder, CalculationGroup calculationGroup, TCalculationGroupContext context, Action calculateAll) + where TCalculationGroupContext : ICalculationContext + { + var performAllItem = new StrictContextMenuItem( + Resources.Calculate_all, + Resources.CalculationGroup_CalculateAll_ToolTip, + Resources.CalculateAllIcon, + (o, args) => calculateAll(calculationGroup, context)); + + if (!calculationGroup.GetCalculations().Any()) + { + performAllItem.Enabled = false; + performAllItem.ToolTipText = Resources.CalculationGroup_CalculateAll_No_calculations_to_run; + } + + builder.AddCustomItem(performAllItem); + } + + /// + /// This method adds a context menu item for performing a calculation. + /// + /// The builder to add the context menu item to. + /// The calculation involved. + /// The calculation context belonging to the calculation. + /// The action that performs the calculation. + public static void AddPerformCalculationItem( + IContextMenuBuilder builder, TCalculation calculation, TCalculationContext context, Action calculate) + where TCalculation : ICalculation + where TCalculationContext : ICalculationContext + { + var calculateItem = new StrictContextMenuItem( + Resources.Calculate, + Resources.Calculate_ToolTip, + Resources.CalculateIcon, + (o, args) => calculate(calculation, context)); + + builder.AddCustomItem(calculateItem); + } + + /// + /// This method adds a context menu item for clearing the output of a calculation. + /// + /// The builder to add the context menu item to. + /// The calculation involved. + public static void AddClearCalculationOutputItem(IContextMenuBuilder builder, ICalculation calculation) + { + var clearOutputItem = new StrictContextMenuItem( + Resources.Clear_output, + Resources.Clear_output_ToolTip, + Resources.ClearIcon, + (o, args) => ClearCalculationOutput(calculation)); + + if (!calculation.HasOutput) + { + clearOutputItem.Enabled = false; + clearOutputItem.ToolTipText = Resources.ClearOutput_No_output_to_clear; + } + + builder.AddCustomItem(clearOutputItem); + } + + /// + /// This method adds a context menu item for changing the relevancy state of a disabled failure mechanism. + /// + /// The builder to add the context menu item to. + /// The failure mechanism context involved. + public static void AddDisabledChangeRelevancyItem(IContextMenuBuilder builder, TFailureMechanismContext failureMechanismContext) + where TFailureMechanismContext : IFailureMechanismContext + { + var changeRelevancyItem = new StrictContextMenuItem( + Resources.FailureMechanismContextMenuStrip_Is_relevant, + Resources.FailureMechanismContextMenuStrip_Is_relevant_Tooltip, + Resources.Checkbox_empty, + (o, args) => + { + failureMechanismContext.WrappedData.IsRelevant = true; + failureMechanismContext.WrappedData.NotifyObservers(); + }); + + builder.AddCustomItem(changeRelevancyItem); + } + + private static void CreateCalculationGroup(CalculationGroup calculationGroup) + { + calculationGroup.Children.Add(new CalculationGroup + { + Name = NamingHelper.GetUniqueName(calculationGroup.Children, RingtoetsCommonDataResources.CalculationGroup_DefaultName, c => c.Name) + }); + + calculationGroup.NotifyObservers(); + } + + private static void ClearAllCalculationOutputInGroup(CalculationGroup calculationGroup) + { + if (MessageBox.Show(Resources.CalculationGroup_ClearOutput_Are_you_sure_clear_all_output, BaseResources.Confirm, MessageBoxButtons.OKCancel) != DialogResult.OK) + { + return; + } + + calculationGroup.ClearCalculationOutput(); + } + + private static void ClearCalculationOutput(ICalculation calculation) + { + if (MessageBox.Show(Resources.Calculation_ContextMenuStrip_Are_you_sure_clear_output, BaseResources.Confirm, MessageBoxButtons.OKCancel) != DialogResult.OK) + { + return; + } + + calculation.ClearOutput(); + calculation.NotifyObservers(); + } + } +} \ No newline at end of file Index: Ringtoets/Common/src/Ringtoets.Common.Forms/TreeNodeInfos/RingtoetsTreeNodeInfoFactory.cs =================================================================== diff -u --- Ringtoets/Common/src/Ringtoets.Common.Forms/TreeNodeInfos/RingtoetsTreeNodeInfoFactory.cs (revision 0) +++ Ringtoets/Common/src/Ringtoets.Common.Forms/TreeNodeInfos/RingtoetsTreeNodeInfoFactory.cs (revision 36b6f1f7c1ddf585689512eb61256d41a1e0ca64) @@ -0,0 +1,303 @@ +// Copyright (C) Stichting Deltares 2016. All rights reserved. +// +// This file is part of Ringtoets. +// +// Ringtoets is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; +using Core.Common.Controls.TreeView; +using Ringtoets.Common.Data.Calculation; +using Ringtoets.Common.Data.FailureMechanism; +using Ringtoets.Common.Forms.PresentationObjects; +using Ringtoets.Common.Forms.Properties; +using RingtoetsCommonDataResources = Ringtoets.Common.Data.Properties.Resources; +using BaseResources = Core.Common.Base.Properties.Resources; + +namespace Ringtoets.Common.Forms.TreeNodeInfos +{ + /// + /// Factory for creating calculation related objects. + /// + public static class RingtoetsTreeNodeInfoFactory + { + /// + /// Creates a object for a calculation group context of the type . + /// + /// The type of calculation group context to create a object for. + /// The function for obtaining the child node objects. + /// The function for obtaining the context menu strip. + /// The action to perform on removing a node. + /// A object. + public static TreeNodeInfo CreateCalculationGroupContextTreeNodeInfo( + Func childNodeObjects, + Func contextMenuStrip, + Action onNodeRemoved) + where TCalculationGroupContext : ICalculationContext + { + return new TreeNodeInfo + { + Text = context => context.WrappedData.Name, + Image = context => Resources.GeneralFolderIcon, + EnsureVisibleOnCreate = (context, parent) => !(parent is IFailureMechanismContext), + ChildNodeObjects = childNodeObjects, + ContextMenuStrip = contextMenuStrip, + CanRename = (context, parentData) => IsNestedGroup(parentData), + OnNodeRenamed = (context, newName) => + { + context.WrappedData.Name = newName; + context.NotifyObservers(); + }, + CanRemove = (context, parentData) => IsNestedGroup(parentData), + OnNodeRemoved = onNodeRemoved, + CanDrag = (context, parentData) => IsNestedGroup(parentData), + CanInsert = CalculationGroupCanDropOrInsert, + CanDrop = CalculationGroupCanDropOrInsert, + OnDrop = CalculationGroupOnDrop + }; + } + + /// + /// Creates a object for a calculation context of the type . + /// + /// The icon of the . + /// The function for obtaining the child node objects. + /// The function for obtaining the context menu strip. + /// The action to perform on removing a node. + /// The type of calculation context to create a object for. + /// A object. + public static TreeNodeInfo CreateCalculationContextTreeNodeInfo( + Bitmap icon, + Func childNodeObjects, + Func contextMenuStrip, + Action onNodeRemoved) + where TCalculationContext : ICalculationContext + { + return new TreeNodeInfo + { + Text = context => context.WrappedData.Name, + Image = context => icon, + EnsureVisibleOnCreate = (context, parent) => true, + ChildNodeObjects = childNodeObjects, + ContextMenuStrip = contextMenuStrip, + CanRename = (context, parent) => true, + OnNodeRenamed = (context, newName) => + { + context.WrappedData.Name = newName; + context.WrappedData.NotifyObservers(); + }, + CanRemove = (context, parentData) => CalculationContextCanRemove(context, parentData), + OnNodeRemoved = onNodeRemoved, + CanDrag = (context, parentData) => true + }; + } + + /// + /// Creates a object for a failure mechanism context of the type . + /// + /// The function for obtaining the child node objects when is true. + /// The function for obtaining the child node objects when is false. + /// The function for obtaining the context menu strip when is true. + /// The function for obtaining the context menu strip when is false. + /// The type of failure mechanism context to create a object for. + /// A object. + public static TreeNodeInfo CreateFailureMechanismContextTreeNodeInfo( + Func enabledChildNodeObjects, + Func disabledChildNodeObjects, + Func enabledContextMenuStrip, + Func disabledContextMenuStrip) + where TFailureMechanismContext : IFailureMechanismContext + { + return new TreeNodeInfo + { + Text = context => context.WrappedData.Name, + ForeColor = context => context.WrappedData.IsRelevant + ? Color.FromKnownColor(KnownColor.ControlText) + : Color.FromKnownColor(KnownColor.GrayText), + Image = context => Resources.FailureMechanismIcon, + ChildNodeObjects = context => context.WrappedData.IsRelevant + ? enabledChildNodeObjects(context) + : disabledChildNodeObjects(context), + ContextMenuStrip = (context, parentData, treeViewControl) => context.WrappedData.IsRelevant + ? enabledContextMenuStrip(context, parentData, treeViewControl) + : disabledContextMenuStrip(context, parentData, treeViewControl) + }; + } + + # region Helper methods for CreateCalculationGroupContextTreeNodeInfo + + private static bool IsNestedGroup(object parentData) + { + return parentData is ICalculationContext; + } + + private static bool CalculationGroupCanDropOrInsert(object draggedData, object targetData) + { + var calculationContext = draggedData as ICalculationContext; + return calculationContext != null && ReferenceEquals(calculationContext.FailureMechanism, ((ICalculationContext) targetData).FailureMechanism); + } + + private static void CalculationGroupOnDrop(object droppedData, object newParentData, object oldParentData, int position, TreeViewControl treeViewControl) + { + ICalculationBase calculationItem = ((ICalculationContext) droppedData).WrappedData; + var originalOwnerContext = oldParentData as ICalculationContext; + var targetContext = newParentData as ICalculationContext; + + if (calculationItem != null && originalOwnerContext != null && targetContext != null) + { + var sourceCalculationGroup = originalOwnerContext.WrappedData; + var targetCalculationGroup = targetContext.WrappedData; + + var isMoveWithinSameContainer = ReferenceEquals(sourceCalculationGroup, targetCalculationGroup); + + DroppingCalculationInContainerStrategy dropHandler = GetDragDropStrategy(isMoveWithinSameContainer, sourceCalculationGroup, targetCalculationGroup); + dropHandler.Execute(droppedData, calculationItem, position, treeViewControl); + } + } + + private static DroppingCalculationInContainerStrategy GetDragDropStrategy(bool isMoveWithinSameContainer, CalculationGroup sourceCalculationGroup, CalculationGroup targetCalculationGroup) + { + if (isMoveWithinSameContainer) + { + return new DroppingCalculationWithinSameContainer(sourceCalculationGroup, targetCalculationGroup); + } + + return new DroppingCalculationToNewContainer(sourceCalculationGroup, targetCalculationGroup); + } + + # region Nested types: DroppingCalculationInContainerStrategy and implementations + + /// + /// Strategy pattern implementation for dealing with drag and drop of a + /// onto data. + /// + private abstract class DroppingCalculationInContainerStrategy + { + protected readonly CalculationGroup targetCalculationGroup; + private readonly CalculationGroup sourceCalculationGroup; + + protected DroppingCalculationInContainerStrategy(CalculationGroup sourceCalculationGroup, CalculationGroup targetCalculationGroup) + { + this.sourceCalculationGroup = sourceCalculationGroup; + this.targetCalculationGroup = targetCalculationGroup; + } + + /// + /// Performs the drag and drop operation. + /// + /// The dragged data. + /// The calculation item wrapped by . + /// The index of the new position within the new owner's collection. + /// The tree view control in which the drag and drop operation is performed. + public virtual void Execute(object draggedData, ICalculationBase calculationBase, int newPosition, TreeViewControl treeViewControl) + { + MoveCalculationItemToNewOwner(calculationBase, newPosition); + + NotifyObservers(); + } + + /// + /// Moves the instance to its new location. + /// + /// The instance to be relocated. + /// The index in the new + /// owner within its . + protected void MoveCalculationItemToNewOwner(ICalculationBase calculationBase, int position) + { + sourceCalculationGroup.Children.Remove(calculationBase); + targetCalculationGroup.Children.Insert(position, calculationBase); + } + + /// + /// Notifies observers of the change in state. + /// + protected virtual void NotifyObservers() + { + sourceCalculationGroup.NotifyObservers(); + } + } + + /// + /// Strategy implementation for rearranging the order of an + /// within a through a drag and drop action. + /// + private class DroppingCalculationWithinSameContainer : DroppingCalculationInContainerStrategy + { + /// + /// Initializes a new instance of the class. + /// + /// The calculation group that is the target of the drag and drop operation. + /// The calculation group that is the original owner of the dragged item. + public DroppingCalculationWithinSameContainer(CalculationGroup sourceCalculationGroup, CalculationGroup targetCalculationGroup) : + base(sourceCalculationGroup, targetCalculationGroup) {} + } + + /// + /// Strategy implementation for moving an from + /// one to another using a drag and drop action. + /// + private class DroppingCalculationToNewContainer : DroppingCalculationInContainerStrategy + { + /// + /// Initializes a new instance of the class. + /// + /// The calculation group that is the original owner of the dragged item. + /// The calculation group that is the target of the drag and drop operation. + public DroppingCalculationToNewContainer(CalculationGroup sourceCalculationGroup, CalculationGroup targetCalculationGroup) : + base(sourceCalculationGroup, targetCalculationGroup) {} + + public override void Execute(object draggedData, ICalculationBase calculationBase, int newPosition, TreeViewControl treeViewControl) + { + MoveCalculationItemToNewOwner(calculationBase, newPosition); + + NotifyObservers(); + + // Try to start a name edit action when an item with the same name was already present + if (targetCalculationGroup.Children.Except(new[] + { + calculationBase + }).Any(c => c.Name.Equals(calculationBase.Name))) + { + treeViewControl.TryRenameNodeForData(draggedData); + } + } + + protected override void NotifyObservers() + { + base.NotifyObservers(); + targetCalculationGroup.NotifyObservers(); + } + } + + # endregion + + # endregion + + #region Helper methods for CreateCalculationContextTreeNodeInfo + + private static bool CalculationContextCanRemove(ICalculationContext calculationContext, object parentNodeData) + { + var calculationGroupContext = parentNodeData as ICalculationContext; + return calculationGroupContext != null && calculationGroupContext.WrappedData.Children.Contains(calculationContext.WrappedData); + } + + #endregion + } +} \ No newline at end of file Index: Ringtoets/Common/test/Ringtoets.Common.Forms.Test/Ringtoets.Common.Forms.Test.csproj =================================================================== diff -u -rb47c41dd3741ada477388e6c8a9224ecb66291e7 -r36b6f1f7c1ddf585689512eb61256d41a1e0ca64 --- Ringtoets/Common/test/Ringtoets.Common.Forms.Test/Ringtoets.Common.Forms.Test.csproj (.../Ringtoets.Common.Forms.Test.csproj) (revision b47c41dd3741ada477388e6c8a9224ecb66291e7) +++ Ringtoets/Common/test/Ringtoets.Common.Forms.Test/Ringtoets.Common.Forms.Test.csproj (.../Ringtoets.Common.Forms.Test.csproj) (revision 36b6f1f7c1ddf585689512eb61256d41a1e0ca64) @@ -66,8 +66,8 @@ - - + + Fisheye: Tag 36b6f1f7c1ddf585689512eb61256d41a1e0ca64 refers to a dead (removed) revision in file `Ringtoets/Common/test/Ringtoets.Common.Forms.Test/TreeNodeInfos/CalculationTreeNodeInfoFactoryTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 36b6f1f7c1ddf585689512eb61256d41a1e0ca64 refers to a dead (removed) revision in file `Ringtoets/Common/test/Ringtoets.Common.Forms.Test/TreeNodeInfos/ContextMenuItemFactoryTest.cs'. Fisheye: No comparison available. Pass `N' to diff? Index: Ringtoets/Common/test/Ringtoets.Common.Forms.Test/TreeNodeInfos/RingtoetsContextMenuItemFactoryTest.cs =================================================================== diff -u --- Ringtoets/Common/test/Ringtoets.Common.Forms.Test/TreeNodeInfos/RingtoetsContextMenuItemFactoryTest.cs (revision 0) +++ Ringtoets/Common/test/Ringtoets.Common.Forms.Test/TreeNodeInfos/RingtoetsContextMenuItemFactoryTest.cs (revision 36b6f1f7c1ddf585689512eb61256d41a1e0ca64) @@ -0,0 +1,680 @@ +// Copyright (C) Stichting Deltares 2016. All rights reserved. +// +// This file is part of Ringtoets. +// +// Ringtoets is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using Core.Common.Base; +using Core.Common.Controls.TreeView; +using Core.Common.Gui.Commands; +using Core.Common.Gui.ContextMenu; +using Core.Common.TestUtil; +using NUnit.Extensions.Forms; +using NUnit.Framework; +using Rhino.Mocks; +using Ringtoets.Common.Data.Calculation; +using Ringtoets.Common.Data.FailureMechanism; +using Ringtoets.Common.Forms.PresentationObjects; +using Ringtoets.Common.Forms.TreeNodeInfos; +using BaseResources = Core.Common.Base.Properties.Resources; +using RingtoetsFormsResources = Ringtoets.Common.Forms.Properties.Resources; + +namespace Ringtoets.Common.Forms.Test.TreeNodeInfos +{ + [TestFixture] + public class RingtoetsContextMenuItemFactoryTest : NUnitFormTest + { + [Test] + public void AddCreateCalculationGroupItem_Always_CreatesDecoratedCalculationGroupItem() + { + // Setup + var mocks = new MockRepository(); + var applicationFeatureCommandHandler = mocks.Stub(); + var exportImportHandler = mocks.Stub(); + var viewCommandsHandler = mocks.StrictMock(); + var treeViewControl = mocks.StrictMock(); + + mocks.ReplayAll(); + + var calculationGroup = new CalculationGroup(); + var menuBuilder = new ContextMenuBuilder(applicationFeatureCommandHandler, exportImportHandler, viewCommandsHandler, calculationGroup, treeViewControl); + + // Call + RingtoetsContextMenuItemFactory.AddCreateCalculationGroupItem(menuBuilder, calculationGroup); + + // Assert + TestHelper.AssertContextMenuStripContainsItem(menuBuilder.Build(), 0, + RingtoetsFormsResources.CalculationGroup_Add_CalculationGroup, + RingtoetsFormsResources.CalculationGroup_Add_CalculationGroup_Tooltip, + RingtoetsFormsResources.AddFolderIcon); + } + + [Test] + public void AddCreateCalculationGroupItem_PerformClickOnCreatedItem_CalculationGroupAdded() + { + // Setup + var mocks = new MockRepository(); + var applicationFeatureCommandHandler = mocks.Stub(); + var exportImportHandler = mocks.Stub(); + var viewCommandsHandler = mocks.StrictMock(); + var treeViewControl = mocks.StrictMock(); + + mocks.ReplayAll(); + + var calculationGroup = new CalculationGroup(); + var menuBuilder = new ContextMenuBuilder(applicationFeatureCommandHandler, exportImportHandler, viewCommandsHandler, calculationGroup, treeViewControl); + RingtoetsContextMenuItemFactory.AddCreateCalculationGroupItem(menuBuilder, calculationGroup); + var contextMenuItem = menuBuilder.Build().Items[0]; + + // Call + contextMenuItem.PerformClick(); + + // Assert + Assert.AreEqual(1, calculationGroup.Children.Count); + Assert.IsTrue(calculationGroup.Children[0] is CalculationGroup); + } + + [Test] + public void AddCreateCalculationItem_Always_CreatesDecoratedCalculationItem() + { + // Setup + var mocks = new MockRepository(); + var failureMechanism = mocks.Stub(); + var applicationFeatureCommandHandler = mocks.Stub(); + var exportImportHandler = mocks.Stub(); + var viewCommandsHandler = mocks.StrictMock(); + var treeViewControl = mocks.StrictMock(); + + mocks.ReplayAll(); + + var calculationGroup = new CalculationGroup(); + var calculationGroupContext = new TestCalculationGroupContext(calculationGroup, failureMechanism); + var menuBuilder = new ContextMenuBuilder(applicationFeatureCommandHandler, exportImportHandler, viewCommandsHandler, calculationGroup, treeViewControl); + + // Call + RingtoetsContextMenuItemFactory.AddCreateCalculationItem(menuBuilder, calculationGroupContext, null); + + // Assert + TestHelper.AssertContextMenuStripContainsItem(menuBuilder.Build(), 0, + RingtoetsFormsResources.CalculationGroup_Add_Calculation, + RingtoetsFormsResources.CalculationGroup_Add_Calculation_Tooltip, + RingtoetsFormsResources.FailureMechanismIcon); + } + + [Test] + public void AddCreateCalculationItem_PerformClickOnCreatedItem_AddCalculationMethodPerformed() + { + // Setup + var mocks = new MockRepository(); + var failureMechanism = mocks.Stub(); + var applicationFeatureCommandHandler = mocks.Stub(); + var exportImportHandler = mocks.Stub(); + var viewCommandsHandler = mocks.StrictMock(); + var treeViewControl = mocks.StrictMock(); + + mocks.ReplayAll(); + + var counter = 0; + var calculationGroup = new CalculationGroup(); + var calculationGroupContext = new TestCalculationGroupContext(calculationGroup, failureMechanism); + var menuBuilder = new ContextMenuBuilder(applicationFeatureCommandHandler, exportImportHandler, viewCommandsHandler, calculationGroup, treeViewControl); + + RingtoetsContextMenuItemFactory.AddCreateCalculationItem(menuBuilder, calculationGroupContext, context => counter++); + var contextMenuItem = menuBuilder.Build().Items[0]; + + // Call + contextMenuItem.PerformClick(); + + // Assert + Assert.AreEqual(1, counter); + } + + [Test] + public void AddClearAllCalculationOutputInGroupItem_GroupWithCalculationOutput_CreatesDecoratedAndEnabledClearItem() + { + // Setup + var mocks = new MockRepository(); + var applicationFeatureCommandHandler = mocks.Stub(); + var exportImportHandler = mocks.Stub(); + var viewCommandsHandler = mocks.StrictMock(); + var treeViewControl = mocks.StrictMock(); + var calculationWithOutput = mocks.StrictMock(); + + calculationWithOutput.Expect(c => c.HasOutput).Return(true); + + mocks.ReplayAll(); + + var calculationGroup = new CalculationGroup + { + Children = + { + calculationWithOutput + } + }; + + var menuBuilder = new ContextMenuBuilder(applicationFeatureCommandHandler, exportImportHandler, viewCommandsHandler, calculationGroup, treeViewControl); + + // Call + RingtoetsContextMenuItemFactory.AddClearAllCalculationOutputInGroupItem(menuBuilder, calculationGroup); + + // Assert + TestHelper.AssertContextMenuStripContainsItem(menuBuilder.Build(), 0, + RingtoetsFormsResources.Clear_all_output, + RingtoetsFormsResources.CalculationGroup_ClearOutput_ToolTip, + RingtoetsFormsResources.ClearIcon); + } + + [Test] + public void AddClearAllCalculationOutputInGroupItem_GroupWithoutCalculationOutput_CreatesDecoratedAndDisabledClearItem() + { + // Setup + var mocks = new MockRepository(); + var applicationFeatureCommandHandler = mocks.Stub(); + var exportImportHandler = mocks.Stub(); + var viewCommandsHandler = mocks.StrictMock(); + var treeViewControl = mocks.StrictMock(); + var calculationWithoutOutput = mocks.StrictMock(); + + calculationWithoutOutput.Expect(c => c.HasOutput).Return(false); + + mocks.ReplayAll(); + + var calculationGroup = new CalculationGroup + { + Children = + { + calculationWithoutOutput + } + }; + + var menuBuilder = new ContextMenuBuilder(applicationFeatureCommandHandler, exportImportHandler, viewCommandsHandler, calculationGroup, treeViewControl); + + // Call + RingtoetsContextMenuItemFactory.AddClearAllCalculationOutputInGroupItem(menuBuilder, calculationGroup); + + // Assert + TestHelper.AssertContextMenuStripContainsItem(menuBuilder.Build(), 0, + RingtoetsFormsResources.Clear_all_output, + RingtoetsFormsResources.CalculationGroup_ClearOutput_No_calculation_with_output_to_clear, + RingtoetsFormsResources.ClearIcon, + false); + } + + [Test] + public void AddClearAllCalculationOutputInGroupItem_PerformClickOnCreatedItemAndConfirmChange_CalculationOutputClearedAndObserversNotified() + { + var messageBoxText = ""; + var messageBoxTitle = ""; + var mocks = new MockRepository(); + var applicationFeatureCommandHandler = mocks.Stub(); + var exportImportHandler = mocks.Stub(); + var viewCommandsHandler = mocks.StrictMock(); + var treeViewControl = mocks.StrictMock(); + var calculationWithOutput1 = mocks.StrictMock(); + var calculationWithOutput2 = mocks.StrictMock(); + var calculationWithoutOutput = mocks.StrictMock(); + + calculationWithOutput1.Stub(c => c.HasOutput).Return(true); + calculationWithOutput2.Stub(c => c.HasOutput).Return(true); + calculationWithoutOutput.Stub(c => c.HasOutput).Return(false); + + calculationWithOutput1.Expect(c => c.ClearOutput()); + calculationWithOutput1.Expect(c => c.NotifyObservers()); + calculationWithOutput2.Expect(c => c.ClearOutput()); + calculationWithOutput2.Expect(c => c.NotifyObservers()); + + mocks.ReplayAll(); + + DialogBoxHandler = (name, wnd) => + { + var messageBox = new MessageBoxTester(wnd); + messageBoxText = messageBox.Text; + messageBoxTitle = messageBox.Title; + + messageBox.ClickOk(); + }; + + var calculationGroup = new CalculationGroup + { + Children = + { + calculationWithOutput1, + new CalculationGroup + { + Children = + { + calculationWithOutput2, + calculationWithoutOutput + } + } + } + }; + + var menuBuilder = new ContextMenuBuilder(applicationFeatureCommandHandler, exportImportHandler, viewCommandsHandler, calculationGroup, treeViewControl); + + RingtoetsContextMenuItemFactory.AddClearAllCalculationOutputInGroupItem(menuBuilder, calculationGroup); + var contextMenuItem = menuBuilder.Build().Items[0]; + + // Call + contextMenuItem.PerformClick(); + + // Assert + Assert.AreEqual(BaseResources.Confirm, messageBoxTitle); + Assert.AreEqual(RingtoetsFormsResources.CalculationGroup_ClearOutput_Are_you_sure_clear_all_output, messageBoxText); + + mocks.VerifyAll(); + } + + [Test] + public void AddClearAllCalculationOutputInGroupItem_PerformClickOnCreatedItemAndCancelChange_CalculationOutputNotCleared() + { + var mocks = new MockRepository(); + var applicationFeatureCommandHandler = mocks.Stub(); + var exportImportHandler = mocks.Stub(); + var viewCommandsHandler = mocks.StrictMock(); + var treeViewControl = mocks.StrictMock(); + var calculationWithOutput1 = mocks.StrictMock(); + var calculationWithOutput2 = mocks.StrictMock(); + var calculationWithoutOutput = mocks.StrictMock(); + + calculationWithOutput1.Stub(c => c.HasOutput).Return(true); + calculationWithOutput2.Stub(c => c.HasOutput).Return(true); + calculationWithoutOutput.Stub(c => c.HasOutput).Return(false); + + mocks.ReplayAll(); + + DialogBoxHandler = (name, wnd) => + { + var messageBox = new MessageBoxTester(wnd); + + messageBox.ClickCancel(); + }; + + var calculationGroup = new CalculationGroup + { + Children = + { + calculationWithOutput1, + new CalculationGroup + { + Children = + { + calculationWithOutput2, + calculationWithoutOutput + } + } + } + }; + + var menuBuilder = new ContextMenuBuilder(applicationFeatureCommandHandler, exportImportHandler, viewCommandsHandler, calculationGroup, treeViewControl); + + RingtoetsContextMenuItemFactory.AddClearAllCalculationOutputInGroupItem(menuBuilder, calculationGroup); + var contextMenuItem = menuBuilder.Build().Items[0]; + + // Call + contextMenuItem.PerformClick(); + + mocks.VerifyAll(); + } + + [Test] + public void AddPerformAllCalculationsInGroupItem_GroupWithCalculations_CreatesDecoratedAndEnabledPerformItem() + { + // Setup + var mocks = new MockRepository(); + var applicationFeatureCommandHandler = mocks.Stub(); + var exportImportHandler = mocks.Stub(); + var viewCommandsHandler = mocks.StrictMock(); + var treeViewControl = mocks.StrictMock(); + var calculation = mocks.StrictMock(); + + mocks.ReplayAll(); + + var calculationGroup = new CalculationGroup + { + Children = + { + calculation + } + }; + + var menuBuilder = new ContextMenuBuilder(applicationFeatureCommandHandler, exportImportHandler, viewCommandsHandler, calculationGroup, treeViewControl); + + // Call + RingtoetsContextMenuItemFactory.AddPerformAllCalculationsInGroupItem(menuBuilder, calculationGroup, null, null); + + // Assert + TestHelper.AssertContextMenuStripContainsItem(menuBuilder.Build(), 0, + RingtoetsFormsResources.Calculate_all, + RingtoetsFormsResources.CalculationGroup_CalculateAll_ToolTip, + RingtoetsFormsResources.CalculateAllIcon); + } + + [Test] + public void AddPerformAllCalculationsInGroupItem_GroupWithoutCalculations_CreatesDecoratedAndDisabledPerformItem() + { + // Setup + var mocks = new MockRepository(); + var applicationFeatureCommandHandler = mocks.Stub(); + var exportImportHandler = mocks.Stub(); + var viewCommandsHandler = mocks.StrictMock(); + var treeViewControl = mocks.StrictMock(); + + mocks.ReplayAll(); + + var calculationGroup = new CalculationGroup(); + var menuBuilder = new ContextMenuBuilder(applicationFeatureCommandHandler, exportImportHandler, viewCommandsHandler, calculationGroup, treeViewControl); + + // Call + RingtoetsContextMenuItemFactory.AddPerformAllCalculationsInGroupItem(menuBuilder, calculationGroup, null, null); + + // Assert + TestHelper.AssertContextMenuStripContainsItem(menuBuilder.Build(), 0, + RingtoetsFormsResources.Calculate_all, + RingtoetsFormsResources.CalculationGroup_CalculateAll_No_calculations_to_run, + RingtoetsFormsResources.CalculateAllIcon, + false); + } + + [Test] + public void AddPerformAllCalculationsInGroupItem_PerformClickOnCreatedItem_PerformAllCalculationMethodPerformed() + { + // Setup + var mocks = new MockRepository(); + var applicationFeatureCommandHandler = mocks.Stub(); + var exportImportHandler = mocks.Stub(); + var viewCommandsHandler = mocks.StrictMock(); + var treeViewControl = mocks.StrictMock(); + var calculation = mocks.StrictMock(); + var failureMechanism = mocks.StrictMock(); + + mocks.ReplayAll(); + + var counter = 0; + var calculationGroup = new CalculationGroup + { + Children = + { + calculation + } + }; + + var calculationGroupContext = new TestCalculationGroupContext(calculationGroup, failureMechanism); + + var menuBuilder = new ContextMenuBuilder(applicationFeatureCommandHandler, exportImportHandler, viewCommandsHandler, calculationGroup, treeViewControl); + + RingtoetsContextMenuItemFactory.AddPerformAllCalculationsInGroupItem(menuBuilder, calculationGroup, calculationGroupContext, (group, context) => counter++); + var contextMenuItem = menuBuilder.Build().Items[0]; + + // Call + contextMenuItem.PerformClick(); + + // Assert + Assert.AreEqual(1, counter); + } + + [Test] + public void AddPerformCalculationItem_Always_CreatesPerformItem() + { + // Setup + var mocks = new MockRepository(); + var applicationFeatureCommandHandler = mocks.Stub(); + var exportImportHandler = mocks.Stub(); + var viewCommandsHandler = mocks.StrictMock(); + var treeViewControl = mocks.StrictMock(); + + mocks.ReplayAll(); + + var calculation = new TestCalculation(); + + var menubuilder = new ContextMenuBuilder(applicationFeatureCommandHandler, exportImportHandler, viewCommandsHandler, calculation, treeViewControl); + + // Call + RingtoetsContextMenuItemFactory.AddPerformCalculationItem(menubuilder, calculation, null, null); + + // Assert + TestHelper.AssertContextMenuStripContainsItem(menubuilder.Build(), 0, + RingtoetsFormsResources.Calculate, + RingtoetsFormsResources.Calculate_ToolTip, + RingtoetsFormsResources.CalculateIcon); + + mocks.VerifyAll(); + } + + [Test] + public void AddPerformCalculationItem_PerformClickOnCreatedItem_PerformCalculationMethod() + { + // Setup + var mocks = new MockRepository(); + var applicationFeatureCommandHandler = mocks.Stub(); + var exportImportHandler = mocks.Stub(); + var viewCommandsHandler = mocks.StrictMock(); + var failureMechanisMock = mocks.StrictMock(); + var treeViewControl = mocks.StrictMock(); + + mocks.ReplayAll(); + + var calculation = new TestCalculation(); + var testCalculationContext = new TestCalculationContext(calculation, failureMechanisMock); + + var counter = 0; + + var menuBuilder = new ContextMenuBuilder(applicationFeatureCommandHandler, exportImportHandler, viewCommandsHandler, calculation, treeViewControl); + RingtoetsContextMenuItemFactory.AddPerformCalculationItem(menuBuilder, calculation, testCalculationContext, (calc, context) => counter++); + var contextMenuItem = menuBuilder.Build().Items[0]; + + // Call + contextMenuItem.PerformClick(); + + // Assert + Assert.AreEqual(1, counter); + mocks.VerifyAll(); + } + + [Test] + public void AddClearCalculationOutputItem_CalculationWithOutput_CreatesDecoratedAndEnabledClearItem() + { + // Setup + var mocks = new MockRepository(); + var applicationFeatureCommandHandler = mocks.Stub(); + var exportImportHandler = mocks.Stub(); + var viewCommandsHandler = mocks.StrictMock(); + var treeViewControl = mocks.StrictMock(); + var calculationWithOutput = mocks.StrictMock(); + + calculationWithOutput.Expect(c => c.HasOutput).Return(true); + + mocks.ReplayAll(); + + var menuBuilder = new ContextMenuBuilder(applicationFeatureCommandHandler, exportImportHandler, viewCommandsHandler, calculationWithOutput, treeViewControl); + + // Call + RingtoetsContextMenuItemFactory.AddClearCalculationOutputItem(menuBuilder, calculationWithOutput); + + // Assert + TestHelper.AssertContextMenuStripContainsItem(menuBuilder.Build(), 0, + RingtoetsFormsResources.Clear_output, + RingtoetsFormsResources.Clear_output_ToolTip, + RingtoetsFormsResources.ClearIcon); + mocks.VerifyAll(); + } + + [Test] + public void AddClearCalculationOutputItem_CalculationWithoutOutput_CreatesDecoratedAndDisabledClearItem() + { + // Setup + var mocks = new MockRepository(); + var applicationFeatureCommandHandler = mocks.Stub(); + var exportImportHandler = mocks.Stub(); + var viewCommandsHandler = mocks.StrictMock(); + var treeViewControl = mocks.StrictMock(); + var calculationWithOutput = mocks.StrictMock(); + + calculationWithOutput.Expect(c => c.HasOutput).Return(false); + + mocks.ReplayAll(); + + var menuBuilder = new ContextMenuBuilder(applicationFeatureCommandHandler, exportImportHandler, viewCommandsHandler, calculationWithOutput, treeViewControl); + + // Call + RingtoetsContextMenuItemFactory.AddClearCalculationOutputItem(menuBuilder, calculationWithOutput); + + // Assert + TestHelper.AssertContextMenuStripContainsItem(menuBuilder.Build(), 0, + RingtoetsFormsResources.Clear_output, + RingtoetsFormsResources.ClearOutput_No_output_to_clear, + RingtoetsFormsResources.ClearIcon, + false); + mocks.VerifyAll(); + } + + [Test] + public void AddClearCalculationOutputItem_PerformClickOnCreatedItemAndConfirmChange_CalculationOutputClearedAndObserversNotified() + { + var messageBoxText = ""; + var messageBoxTitle = ""; + var mocks = new MockRepository(); + var applicationFeatureCommandHandler = mocks.Stub(); + var exportImportHandler = mocks.Stub(); + var viewCommandsHandler = mocks.StrictMock(); + var treeViewControl = mocks.StrictMock(); + var calculationWithOutput = mocks.StrictMock(); + + calculationWithOutput.Stub(c => c.HasOutput).Return(true); + + calculationWithOutput.Expect(c => c.ClearOutput()); + calculationWithOutput.Expect(c => c.NotifyObservers()); + + mocks.ReplayAll(); + + DialogBoxHandler = (name, wnd) => + { + var messageBox = new MessageBoxTester(wnd); + messageBoxText = messageBox.Text; + messageBoxTitle = messageBox.Title; + + messageBox.ClickOk(); + }; + + var menuBuilder = new ContextMenuBuilder(applicationFeatureCommandHandler, exportImportHandler, viewCommandsHandler, calculationWithOutput, treeViewControl); + + RingtoetsContextMenuItemFactory.AddClearCalculationOutputItem(menuBuilder, calculationWithOutput); + var contextMenuItem = menuBuilder.Build().Items[0]; + + // Call + contextMenuItem.PerformClick(); + + // Assert + Assert.AreEqual(BaseResources.Confirm, messageBoxTitle); + Assert.AreEqual(RingtoetsFormsResources.Calculation_ContextMenuStrip_Are_you_sure_clear_output, messageBoxText); + + mocks.VerifyAll(); + } + + [Test] + public void AddClearCalculationOutputItem_PerformClickOnCreatedItemAndCancelChange_CalculationOutputNotCleared() + { + var mocks = new MockRepository(); + var applicationFeatureCommandHandler = mocks.Stub(); + var exportImportHandler = mocks.Stub(); + var viewCommandsHandler = mocks.StrictMock(); + var treeViewControl = mocks.StrictMock(); + var calculationWithOutput = mocks.StrictMock(); + + calculationWithOutput.Stub(c => c.HasOutput).Return(true); + + mocks.ReplayAll(); + + DialogBoxHandler = (name, wnd) => + { + var messageBox = new MessageBoxTester(wnd); + + messageBox.ClickCancel(); + }; + + var menuBuilder = new ContextMenuBuilder(applicationFeatureCommandHandler, exportImportHandler, viewCommandsHandler, calculationWithOutput, treeViewControl); + + RingtoetsContextMenuItemFactory.AddClearCalculationOutputItem(menuBuilder, calculationWithOutput); + var contextMenuItem = menuBuilder.Build().Items[0]; + + // Call + contextMenuItem.PerformClick(); + + mocks.VerifyAll(); + } + + # region Nested types + + private class TestCalculationGroupContext : Observable, ICalculationContext + { + public TestCalculationGroupContext(CalculationGroup wrappedData, IFailureMechanism failureMechanism) + { + WrappedData = wrappedData; + FailureMechanism = failureMechanism; + } + + public CalculationGroup WrappedData { get; private set; } + + public IFailureMechanism FailureMechanism { get; private set; } + } + + private class TestCalculationContext : Observable, ICalculationContext + { + public TestCalculationContext(TestCalculation wrappedData, IFailureMechanism failureMechanism) + { + WrappedData = wrappedData; + FailureMechanism = failureMechanism; + } + + public TestCalculation WrappedData { get; private set; } + + public IFailureMechanism FailureMechanism { get; private set; } + } + + private class TestCalculation : Observable, ICalculation + { + public TestCalculation() + { + Name = "Nieuwe berekening"; + } + + public string Name { get; set; } + + public string Comments { get; set; } + + public bool HasOutput + { + get + { + return false; + } + } + + public void ClearOutput() { } + + public void ClearHydraulicBoundaryLocation() { } + + public ICalculationInput GetObservableInput() + { + return null; + } + } + + # endregion + } +} Index: Ringtoets/Common/test/Ringtoets.Common.Forms.Test/TreeNodeInfos/RingtoetsTreeNodeInfoFactoryTest.cs =================================================================== diff -u --- Ringtoets/Common/test/Ringtoets.Common.Forms.Test/TreeNodeInfos/RingtoetsTreeNodeInfoFactoryTest.cs (revision 0) +++ Ringtoets/Common/test/Ringtoets.Common.Forms.Test/TreeNodeInfos/RingtoetsTreeNodeInfoFactoryTest.cs (revision 36b6f1f7c1ddf585689512eb61256d41a1e0ca64) @@ -0,0 +1,1155 @@ +// Copyright (C) Stichting Deltares 2016. All rights reserved. +// +// This file is part of Ringtoets. +// +// Ringtoets is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; +using Core.Common.Base; +using Core.Common.Controls.TreeView; +using Core.Common.TestUtil; +using NUnit.Framework; +using Rhino.Mocks; +using Ringtoets.Common.Data.AssessmentSection; +using Ringtoets.Common.Data.Calculation; +using Ringtoets.Common.Data.FailureMechanism; +using Ringtoets.Common.Forms.PresentationObjects; +using Ringtoets.Common.Forms.TreeNodeInfos; +using BaseResources = Core.Common.Base.Properties.Resources; +using RingtoetsFormsResources = Ringtoets.Common.Forms.Properties.Resources; + +namespace Ringtoets.Common.Forms.Test.TreeNodeInfos +{ + [TestFixture] + public class RingtoetsTreeNodeInfoFactoryTest + { + # region CreateCalculationGroupContextTreeNodeInfo + + [Test] + public void CreateCalculationGroupContextTreeNodeInfo_Always_ExpectedPropertiesSet() + { + // Setup + Func childNodeObjects = context => new object[0]; + Func contextMenuStrip = (context, parent, treeViewControl) => new ContextMenuStrip(); + Action onNodeRemoved = (context, parent) => { }; + + // Call + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateCalculationGroupContextTreeNodeInfo(childNodeObjects, contextMenuStrip, onNodeRemoved); + + // Assert + Assert.AreEqual(typeof(TestCalculationGroupContext), treeNodeInfo.TagType); + Assert.AreSame(childNodeObjects, treeNodeInfo.ChildNodeObjects); + Assert.AreSame(contextMenuStrip, treeNodeInfo.ContextMenuStrip); + Assert.AreSame(onNodeRemoved, treeNodeInfo.OnNodeRemoved); + Assert.IsNull(treeNodeInfo.ForeColor); + Assert.IsNull(treeNodeInfo.CanCheck); + Assert.IsNull(treeNodeInfo.IsChecked); + Assert.IsNull(treeNodeInfo.OnNodeChecked); + } + + [Test] + public void Text_CalculationGroup_Always_ReturnsWrappedDataName() + { + // Setup + var mocks = new MockRepository(); + var failureMechanismMock = mocks.StrictMock(); + + mocks.ReplayAll(); + + var groupName = "testName"; + var group = new CalculationGroup + { + Name = groupName + }; + var groupContext = new TestCalculationGroupContext(group, failureMechanismMock); + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateCalculationGroupContextTreeNodeInfo(null, null, null); + + // Call + var text = treeNodeInfo.Text(groupContext); + + // Assert + Assert.AreEqual(groupName, text); + mocks.VerifyAll(); + } + + [Test] + public void Image_CalculationGroup_Always_ReturnsFolderIcon() + { + // Setup + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateCalculationGroupContextTreeNodeInfo(null, null, null); + + // Call + var image = treeNodeInfo.Image(null); + + // Assert + TestHelper.AssertImagesAreEqual(RingtoetsFormsResources.GeneralFolderIcon, image); + } + + [Test] + public void EnsureVisibleOnCreate_CalculationGroup_ForFailureMechanismCalculationGroup_ReturnsFalse() + { + // Setup + var mocks = new MockRepository(); + var failureMechanismMock = mocks.StrictMock>(); + mocks.ReplayAll(); + + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateCalculationGroupContextTreeNodeInfo(null, null, null); + // Call + var result = treeNodeInfo.EnsureVisibleOnCreate(null, failureMechanismMock); + + // Assert + Assert.IsFalse(result); + mocks.VerifyAll(); + } + + [Test] + public void EnsureVisibleOnCreate_CalculationGroup_AnyOtherObject_ReturnsTrue() + { + // Setup + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateCalculationGroupContextTreeNodeInfo(null, null, null); + + // Call + var result = treeNodeInfo.EnsureVisibleOnCreate(null, null); + + // Assert + Assert.IsTrue(result); + } + + [Test] + public void CanRenameNode_CalculationGroup_NestedCalculationGroup_ReturnsTrue() + { + // Setup + var mocks = new MockRepository(); + var calculationGroupMock = mocks.StrictMock(); + var failureMechanismMock = mocks.StrictMock(); + + mocks.ReplayAll(); + + var groupContext = new TestCalculationGroupContext(calculationGroupMock, failureMechanismMock); + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateCalculationGroupContextTreeNodeInfo(null, null, null); + + // Call + bool isRenamingAllowed = treeNodeInfo.CanRename(null, groupContext); + + // Assert + Assert.IsTrue(isRenamingAllowed); + mocks.VerifyAll(); + } + + [Test] + public void CanRenameNode_CalculationGroup_WithoutParentNodeDefaultBehavior_ReturnsFalse() + { + // Setup + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateCalculationGroupContextTreeNodeInfo(null, null, null); + + // Call + bool isRenamingAllowed = treeNodeInfo.CanRename(null, null); + + // Assert + Assert.IsFalse(isRenamingAllowed); + } + + [Test] + public void OnNodeRenamed_CalculationGroup_WithData_RenameGroupAndNotifyObservers() + { + // Setup + var mocks = new MockRepository(); + var observer = mocks.StrictMock(); + var failureMechanismMock = mocks.StrictMock(); + + observer.Expect(o => o.UpdateObserver()); + + mocks.ReplayAll(); + + const string newName = "new name"; + var group = new CalculationGroup(); + var nodeData = new TestCalculationGroupContext(group, failureMechanismMock); + + nodeData.Attach(observer); + + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateCalculationGroupContextTreeNodeInfo(null, null, null); + + // Call + treeNodeInfo.OnNodeRenamed(nodeData, newName); + + // Assert + Assert.AreEqual(newName, group.Name); + mocks.VerifyAll(); + } + + [Test] + public void CanRemove_CalculationGroup_NestedCalculationGroup_ReturnsTrue() + { + // Setup + var mocks = new MockRepository(); + var failureMechanismMock = mocks.StrictMock(); + mocks.ReplayAll(); + + var nodeData = new TestCalculationGroupContext(new CalculationGroup(), failureMechanismMock); + var parentNodeData = new TestCalculationGroupContext(new CalculationGroup(), failureMechanismMock); + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateCalculationGroupContextTreeNodeInfo(null, null, null); + + // Call + bool isRemovalAllowed = treeNodeInfo.CanRemove(nodeData, parentNodeData); + + // Assert + Assert.IsTrue(isRemovalAllowed); + mocks.VerifyAll(); + } + + [Test] + public void CanRemove_CalculationGroup_WithoutParentNodeDefaultBehavior_ReturnsFalse() + { + // Setup + var mocks = new MockRepository(); + var failureMechanismMock = mocks.StrictMock(); + mocks.ReplayAll(); + + var nodeData = new TestCalculationGroupContext(new CalculationGroup(), failureMechanismMock); + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateCalculationGroupContextTreeNodeInfo(null, null, null); + + // Call + bool isRemovalAllowed = treeNodeInfo.CanRemove(nodeData, null); + + // Assert + Assert.IsFalse(isRemovalAllowed); + mocks.VerifyAll(); + } + + [Test] + public void CanDrag_CalculationGroup_NestedCalculationGroup_ReturnsTrue() + { + // Setup + var mocks = new MockRepository(); + var failureMechanismMock = mocks.StrictMock(); + + mocks.ReplayAll(); + + var groupContext = new TestCalculationGroupContext(new CalculationGroup(), failureMechanismMock); + var parentGroupContext = new TestCalculationGroupContext(new CalculationGroup(), failureMechanismMock); + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateCalculationGroupContextTreeNodeInfo(null, null, null); + + // Call + var canDrag = treeNodeInfo.CanDrag(groupContext, parentGroupContext); + + // Assert + Assert.IsTrue(canDrag); + } + + [Test] + public void CanDrag_CalculationGroup_WithoutParentNodeDefaultBehavior_ReturnsFalse() + { + // Setup + var mocks = new MockRepository(); + var failureMechanismMock = mocks.StrictMock(); + + mocks.ReplayAll(); + + var groupContext = new TestCalculationGroupContext(new CalculationGroup(), failureMechanismMock); + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateCalculationGroupContextTreeNodeInfo(null, null, null); + + // Call + var canDrag = treeNodeInfo.CanDrag(groupContext, null); + + // Assert + Assert.IsFalse(canDrag); + } + + [Test] + [Combinatorial] + public void CanDropOrCanInsert_CalculationGroup_DragCalculationItemOntoGroupNotContainingItem_ReturnsTrue( + [Values(DragDropTestMethod.CanDrop, DragDropTestMethod.CanInsert)] DragDropTestMethod methodToTest, + [Values(CalculationItemType.Calculation, CalculationItemType.Group)] CalculationItemType draggedItemType) + { + // Setup + var mocks = new MockRepository(); + var failureMechanism = mocks.StrictMock(); + + mocks.ReplayAll(); + + object draggedItemContext; + ICalculationBase draggedItem; + CreateCalculationItemAndContext(draggedItemType, out draggedItem, out draggedItemContext, failureMechanism); + + CalculationGroup targetGroup; + TestCalculationGroupContext targetGroupContext; + CreateCalculationGroupAndContext(out targetGroup, out targetGroupContext, failureMechanism); + + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateCalculationGroupContextTreeNodeInfo(null, null, null); + + switch (methodToTest) + { + case DragDropTestMethod.CanDrop: + // Call + var canDrop = treeNodeInfo.CanDrop(draggedItemContext, targetGroupContext); + + // Assert + Assert.IsTrue(canDrop); + break; + case DragDropTestMethod.CanInsert: + // Call + bool canInsert = treeNodeInfo.CanInsert(draggedItemContext, targetGroupContext); + + // Assert + Assert.IsTrue(canInsert); + break; + default: + Assert.Fail(methodToTest + " not supported."); + break; + } + mocks.VerifyAll(); + } + + [Test] + [Combinatorial] + public void CanDropOrInsert_CalculationGroup_DragCalculationItemOntoGroupNotContainingItemOtherFailureMechanism_ReturnsFalse( + [Values(DragDropTestMethod.CanDrop, DragDropTestMethod.CanInsert)] DragDropTestMethod methodToTest, + [Values(CalculationItemType.Calculation, CalculationItemType.Group)] CalculationItemType draggedItemType) + { + // Setup + var mocks = new MockRepository(); + var sourceFailureMechanism = mocks.StrictMock(); + var targetFailureMechanism = mocks.StrictMock(); + + mocks.ReplayAll(); + + object draggedItemContext; + ICalculationBase draggedItem; + CreateCalculationItemAndContext(draggedItemType, out draggedItem, out draggedItemContext, targetFailureMechanism); + + CalculationGroup targetGroup; + TestCalculationGroupContext targetGroupContext; + CreateCalculationGroupAndContext(out targetGroup, out targetGroupContext, sourceFailureMechanism); + + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateCalculationGroupContextTreeNodeInfo(null, null, null); + + switch (methodToTest) + { + case DragDropTestMethod.CanDrop: + // Call + var canDrop = treeNodeInfo.CanDrop(draggedItemContext, targetGroupContext); + + // Assert + Assert.IsFalse(canDrop); + break; + case DragDropTestMethod.CanInsert: + // Call + bool canInsert = treeNodeInfo.CanInsert(draggedItemContext, targetGroupContext); + + // Assert + Assert.IsFalse(canInsert); + break; + default: + Assert.Fail(methodToTest + " not supported."); + break; + } + mocks.VerifyAll(); + } + + [Test] + [Combinatorial] + public void OnDrop_CalculationGroup_DragCalculationItemOntoGroupEnd_MoveCalculationItemToNewGroup( + [Values(CalculationItemType.Calculation, CalculationItemType.Group)] CalculationItemType draggedItemType) + { + // Setup + var mocks = new MockRepository(); + var treeViewControlMock = mocks.StrictMock(); + var failureMechanismMock = mocks.StrictMock(); + var originalOwnerObserver = mocks.StrictMock(); + var newOwnerObserver = mocks.StrictMock(); + + originalOwnerObserver.Expect(o => o.UpdateObserver()); + newOwnerObserver.Expect(o => o.UpdateObserver()); + + mocks.ReplayAll(); + + ICalculationBase draggedItem; + object draggedItemContext; + CreateCalculationItemAndContext(draggedItemType, out draggedItem, out draggedItemContext, failureMechanismMock); + + CalculationGroup originalOwnerGroup; + TestCalculationGroupContext originalOwnerGroupContext; + CreateCalculationGroupAndContext(out originalOwnerGroup, out originalOwnerGroupContext, failureMechanismMock); + originalOwnerGroup.Children.Add(draggedItem); + + CalculationGroup newOwnerGroup; + TestCalculationGroupContext newOwnerGroupContext; + CreateCalculationGroupAndContext(out newOwnerGroup, out newOwnerGroupContext, failureMechanismMock); + + originalOwnerGroup.Attach(originalOwnerObserver); + newOwnerGroup.Attach(newOwnerObserver); + + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateCalculationGroupContextTreeNodeInfo(null, null, null); + + // Precondition + CollectionAssert.Contains(originalOwnerGroup.Children, draggedItem); + CollectionAssert.DoesNotContain(newOwnerGroup.Children, draggedItem); + + // Call + treeNodeInfo.OnDrop(draggedItemContext, newOwnerGroupContext, originalOwnerGroupContext, 0, treeViewControlMock); + + // Assert + CollectionAssert.DoesNotContain(originalOwnerGroup.Children, draggedItem); + CollectionAssert.Contains(newOwnerGroup.Children, draggedItem); + Assert.AreSame(draggedItem, newOwnerGroup.Children.Last(), + "Dragging node at the end of the target TestCalculationGroup should put the dragged data at the end of 'newOwnerGroup'."); + + mocks.VerifyAll(); + } + + [Test] + [Combinatorial] + public void OnDrop_CalculationGroup_InsertCalculationItemAtDifferentLocationWithinSameGroup_ChangeItemIndexOfCalculationItem( + [Values(CalculationItemType.Calculation, CalculationItemType.Group)] CalculationItemType draggedItemType, + [Values(0, 2)] int newIndex) + { + // Setup + var mocks = new MockRepository(); + var treeViewControlMock = mocks.StrictMock(); + var failureMechanismMock = mocks.StrictMock(); + var existingItemStub = mocks.Stub(); + var originalOwnerObserver = mocks.StrictMock(); + + existingItemStub.Stub(ci => ci.Name).Return(""); + originalOwnerObserver.Expect(o => o.UpdateObserver()); + + mocks.ReplayAll(); + + const string name = "Very cool name"; + + object draggedItemContext; + ICalculationBase draggedItem; + CreateCalculationItemAndContext(draggedItemType, out draggedItem, out draggedItemContext, failureMechanismMock, name); + + CalculationGroup originalOwnerGroup; + TestCalculationGroupContext originalOwnerGroupContext; + CreateCalculationGroupAndContext(out originalOwnerGroup, out originalOwnerGroupContext, failureMechanismMock); + + originalOwnerGroup.Children.Add(existingItemStub); + originalOwnerGroup.Children.Add(draggedItem); + originalOwnerGroup.Children.Add(existingItemStub); + + originalOwnerGroup.Attach(originalOwnerObserver); + + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateCalculationGroupContextTreeNodeInfo(null, null, null); + + // Precondition + CollectionAssert.Contains(originalOwnerGroup.Children, draggedItem); + + // Call + treeNodeInfo.OnDrop(draggedItemContext, originalOwnerGroupContext, originalOwnerGroupContext, newIndex, treeViewControlMock); + + // Assert + CollectionAssert.Contains(originalOwnerGroup.Children, draggedItem); + Assert.AreNotSame(draggedItem, originalOwnerGroup.Children[1], + "Should have removed 'draggedItem' from its original location in the collection."); + Assert.AreSame(draggedItem, originalOwnerGroup.Children[newIndex], + "Dragging node to specific location within owning TestCalculationGroup should put the dragged data at that index."); + Assert.AreEqual(name, draggedItem.Name, + "No renaming should occur when dragging within the same TestCalculationGroup."); + + mocks.VerifyAll(); + } + + [Test] + [Combinatorial] + public void OnDrop_CalculationGroup_DragCalculationItemOntoGroupWithSameNamedItem_MoveCalculationItemToNewGroupAndRename( + [Values(CalculationItemType.Calculation, CalculationItemType.Group)] CalculationItemType draggedItemType) + { + // Setup + var mocks = new MockRepository(); + var treeViewControlMock = mocks.StrictMock(); + var failureMechanismMock = mocks.StrictMock(); + + ICalculationBase draggedItem; + object draggedItemContext; + CreateCalculationItemAndContext(draggedItemType, out draggedItem, out draggedItemContext, failureMechanismMock); + + CalculationGroup originalOwnerGroup; + TestCalculationGroupContext originalOwnerGroupContext; + CreateCalculationGroupAndContext(out originalOwnerGroup, out originalOwnerGroupContext, failureMechanismMock); + originalOwnerGroup.Children.Add(draggedItem); + + CalculationGroup newOwnerGroup; + TestCalculationGroupContext newOwnerGroupContext; + CreateCalculationGroupAndContext(out newOwnerGroup, out newOwnerGroupContext, failureMechanismMock); + + var sameNamedItem = mocks.Stub(); + sameNamedItem.Stub(sni => sni.Name).Return(draggedItem.Name); + + var originalOwnerObserver = mocks.StrictMock(); + originalOwnerObserver.Expect(o => o.UpdateObserver()); + + var newOwnerObserver = mocks.StrictMock(); + newOwnerObserver.Expect(o => o.UpdateObserver()); + + treeViewControlMock.Expect(tvc => tvc.TryRenameNodeForData(draggedItemContext)); + + mocks.ReplayAll(); + + newOwnerGroup.Children.Add(sameNamedItem); + + originalOwnerGroup.Attach(originalOwnerObserver); + newOwnerGroup.Attach(newOwnerObserver); + + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateCalculationGroupContextTreeNodeInfo(null, null, null); + + // Precondition + CollectionAssert.Contains(originalOwnerGroup.Children, draggedItem); + CollectionAssert.DoesNotContain(newOwnerGroup.Children, draggedItem); + CollectionAssert.Contains(newOwnerGroup.Children.Select(c => c.Name), draggedItem.Name, + "Name of the dragged item should already exist in new owner."); + + // Call + treeNodeInfo.OnDrop(draggedItemContext, newOwnerGroupContext, originalOwnerGroupContext, 0, treeViewControlMock); + + // Assert + CollectionAssert.DoesNotContain(originalOwnerGroup.Children, draggedItem); + CollectionAssert.Contains(newOwnerGroup.Children, draggedItem); + Assert.AreSame(draggedItem, newOwnerGroup.Children.First(), + "Dragging to insert node at start of newOwnerGroup should place the node at the start of the list."); + switch (draggedItemType) + { + case CalculationItemType.Calculation: + Assert.AreEqual("Nieuwe berekening", draggedItem.Name); + break; + case CalculationItemType.Group: + Assert.AreEqual("Nieuwe map", draggedItem.Name); + break; + } + + mocks.VerifyAll(); + } + + /// + /// Creates an instance of and the corresponding . + /// + /// The created group without any children. + /// The context object for , without any other data. + /// The failure mechanism the item and context it belong to. + private void CreateCalculationGroupAndContext(out CalculationGroup data, out TestCalculationGroupContext dataContext, IFailureMechanism failureMechanism) + { + data = new CalculationGroup(); + dataContext = new TestCalculationGroupContext(data, failureMechanism); + } + + /// + /// Creates an instance of and the corresponding context. + /// + /// Defines the implementation of to be constructed. + /// Output: The concrete create class based on . + /// Output: The context corresponding with . + /// The failure mechanism the item and context belong to. + /// Optional: The name of . + /// + private static void CreateCalculationItemAndContext(CalculationItemType type, out ICalculationBase data, out object dataContext, IFailureMechanism failureMechanism, string initialName = null) + { + switch (type) + { + case CalculationItemType.Calculation: + var calculation = new TestCalculation(); + if (initialName != null) + { + calculation.Name = initialName; + } + data = calculation; + dataContext = new TestCalculationContext(calculation, failureMechanism); + break; + case CalculationItemType.Group: + var group = new CalculationGroup(); + if (initialName != null) + { + group.Name = initialName; + } + data = group; + dataContext = new TestCalculationGroupContext(group, failureMechanism); + break; + default: + throw new NotSupportedException(); + } + } + + #endregion + + #region CreateCalculationContextTreeNodeInfo + + [Test] + public void CreateCalculationContextTreeNodeInfo_Always_ExpectedPropertiesSet() + { + // Setup + var icon = RingtoetsFormsResources.CalculateIcon; + Func childNodeObjects = context => new object[0]; + Func contextMenuStrip = (context, parent, treeViewControl) => new ContextMenuStrip(); + Action onNodeRemoved = (context, parent) => { }; + + // Call + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateCalculationContextTreeNodeInfo(icon, childNodeObjects, contextMenuStrip, onNodeRemoved); + + // Assert + Assert.AreEqual(typeof(TestCalculationContext), treeNodeInfo.TagType); + TestHelper.AssertImagesAreEqual(icon, treeNodeInfo.Image(null)); + Assert.AreSame(childNodeObjects, treeNodeInfo.ChildNodeObjects); + Assert.AreSame(contextMenuStrip, treeNodeInfo.ContextMenuStrip); + Assert.AreSame(onNodeRemoved, treeNodeInfo.OnNodeRemoved); + Assert.IsNull(treeNodeInfo.ForeColor); + Assert.IsNull(treeNodeInfo.CanCheck); + Assert.IsNull(treeNodeInfo.IsChecked); + Assert.IsNull(treeNodeInfo.OnNodeChecked); + } + + [Test] + public void TextOfCalculationContextTreeNodeInfo_Always_ReturnsWrappedDataName() + { + // Setup + var mocks = new MockRepository(); + var failureMechanismMock = mocks.StrictMock(); + + mocks.ReplayAll(); + + var calculationName = "calculationName"; + var calculation = new TestCalculation + { + Name = calculationName + }; + + var context = new TestCalculationContext(calculation, failureMechanismMock); + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateCalculationContextTreeNodeInfo(null, null, null, null); + + // Call + var text = treeNodeInfo.Text(context); + + // Assert + Assert.AreEqual(calculationName, text); + mocks.VerifyAll(); + } + + [Test] + public void EnsureVisibleOnCreateOfCalculationContextTreeNodeInfo_Always_ReturnsTrue() + { + // Setup + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateCalculationContextTreeNodeInfo(null, null, null, null); + + // Call + var result = treeNodeInfo.EnsureVisibleOnCreate(null, null); + + // Assert + Assert.IsTrue(result); + } + + [Test] + public void CanRenameCalculationContextTreeNodeInfo_Always_ReturnTrue() + { + // Setup + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateCalculationContextTreeNodeInfo(null, null, null, null); + + // Call + var renameAllowed = treeNodeInfo.CanRename(null, null); + + // Assert + Assert.IsTrue(renameAllowed); + } + + [Test] + public void OnNodeRenamedOfCalculationContextTreeNodeInfo_Always_SetNewNameToCalculationItemAndNotifyObserver() + { + // Setup + var mocks = new MockRepository(); + var observerMock = mocks.StrictMock(); + observerMock.Expect(o => o.UpdateObserver()); + + var failureMechanismMock = mocks.StrictMock(); + mocks.ReplayAll(); + + var calculation = new TestCalculation + { + Name = "" + }; + + var context = new TestCalculationContext(calculation, failureMechanismMock); + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateCalculationContextTreeNodeInfo(null, null, null, null); + + context.WrappedData.Attach(observerMock); + + // Call + const string newName = ""; + treeNodeInfo.OnNodeRenamed(context, newName); + + // Assert + Assert.AreEqual(newName, calculation.Name); + mocks.VerifyAll(); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void CanRemoveCalculationContextTreeNodeInfo_ParentIsCalculationGroupWithCalculation_ReturnTrue(bool groupNameEditable) + { + // Setup + var calculationToBeRemoved = new TestCalculation(); + var group = new CalculationGroup("", groupNameEditable); + group.Children.Add(calculationToBeRemoved); + + var mocks = new MockRepository(); + var failureMechanismMock = mocks.StrictMock(); + mocks.ReplayAll(); + + var context = new TestCalculationContext(calculationToBeRemoved, failureMechanismMock); + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateCalculationContextTreeNodeInfo(null, null, null, null); + + var groupContext = new TestCalculationGroupContext(group, failureMechanismMock); + + // Call + bool removalAllowed = treeNodeInfo.CanRemove(context, groupContext); + + // Assert + Assert.IsTrue(removalAllowed); + } + + [Test] + [TestCase(true)] + [TestCase(false)] + public void CanRemoveCalculationContextTreeNodeInfo_ParentIsCalculationGroupWithoutCalculation_ReturnFalse(bool groupNameEditable) + { + // Setup + var calculationToBeRemoved = new TestCalculation(); + var group = new CalculationGroup("", groupNameEditable); + + var mocks = new MockRepository(); + var failureMechanismMock = mocks.StrictMock(); + mocks.ReplayAll(); + + var context = new TestCalculationContext(calculationToBeRemoved, failureMechanismMock); + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateCalculationContextTreeNodeInfo(null, null, null, null); + + var groupContext = new TestCalculationGroupContext(group, failureMechanismMock); + + // Call + bool removalAllowed = treeNodeInfo.CanRemove(context, groupContext); + + // Assert + Assert.IsFalse(removalAllowed); + } + + [Test] + public void CanRemoveCalculationContextTreeNodeInfo_EverythingElse_ReturnFalse() + { + // Setup + var mocks = new MockRepository(); + var dataMock = mocks.StrictMock(); + var failureMechanismMock = mocks.StrictMock(); + mocks.ReplayAll(); + + var nodeMock = new TestCalculationContext(new TestCalculation(), failureMechanismMock); + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateCalculationContextTreeNodeInfo(null, null, null, null); + + // Call + bool removalAllowed = treeNodeInfo.CanRemove(nodeMock, dataMock); + + // Assert + Assert.IsFalse(removalAllowed); + mocks.VerifyAll(); // Expect no calls on arguments + } + + [Test] + public void CanDragCalculationContextTreeNodeInfo_Always_ReturnTrue() + { + // Setup + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateCalculationContextTreeNodeInfo(null, null, null, null); + + // Call + var canDrag = treeNodeInfo.CanDrag(null, null); + + // Assert + Assert.IsTrue(canDrag); + } + + #endregion + + # region CreateFailureMechanismContextTreeNodeInfo + + [Test] + public void CreateFailureMechanismContextTreeNodeInfo_Always_ExpectedPropertiesSet() + { + // Call + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateFailureMechanismContextTreeNodeInfo>(null, null, null, null); + + // Assert + Assert.AreEqual(typeof(FailureMechanismContext), treeNodeInfo.TagType); + Assert.IsNotNull(treeNodeInfo.Text); + Assert.IsNotNull(treeNodeInfo.Image); + Assert.IsNotNull(treeNodeInfo.ForeColor); + Assert.IsNotNull(treeNodeInfo.ChildNodeObjects); + Assert.IsNotNull(treeNodeInfo.ContextMenuStrip); + Assert.IsNull(treeNodeInfo.EnsureVisibleOnCreate); + Assert.IsNull(treeNodeInfo.CanRename); + Assert.IsNull(treeNodeInfo.OnNodeRenamed); + Assert.IsNull(treeNodeInfo.CanRemove); + Assert.IsNull(treeNodeInfo.OnNodeRemoved); + Assert.IsNull(treeNodeInfo.CanCheck); + Assert.IsNull(treeNodeInfo.IsChecked); + Assert.IsNull(treeNodeInfo.OnNodeChecked); + Assert.IsNull(treeNodeInfo.CanDrag); + Assert.IsNull(treeNodeInfo.CanDrop); + Assert.IsNull(treeNodeInfo.CanInsert); + Assert.IsNull(treeNodeInfo.OnDrop); + } + + [Test] + public void Text_FailureMechanism_Always_ReturnsWrappedDataName() + { + // Setup + const string name = "A"; + + var mocks = new MockRepository(); + var failureMechanism = mocks.Stub(); + var assessmentSection = mocks.Stub(); + + failureMechanism.Stub(fm => fm.Name).Return(name); + + mocks.ReplayAll(); + + var context = new TestFailureMechanismContext(failureMechanism, assessmentSection); + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateFailureMechanismContextTreeNodeInfo(null, null, null, null); + + // Call + string text = treeNodeInfo.Text(context); + + // Assert + Assert.AreEqual(name, text); + mocks.VerifyAll(); + } + + [Test] + public void Image_FailureMechanism_Always_ReturnsFailureMechanismIcon() + { + // Setup + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateFailureMechanismContextTreeNodeInfo>(null, null, null, null); + + // Call + Image image = treeNodeInfo.Image(null); + + // Assert + TestHelper.AssertImagesAreEqual(RingtoetsFormsResources.FailureMechanismIcon, image); + } + + [Test] + public void ForeColor_FailureMechanismIsRelevant_ReturnsControlText() + { + // Setup + var mocks = new MockRepository(); + var failureMechanism = mocks.Stub(); + var assessmentSection = mocks.Stub(); + mocks.ReplayAll(); + + failureMechanism.IsRelevant = true; + + var context = new TestFailureMechanismContext(failureMechanism, assessmentSection); + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateFailureMechanismContextTreeNodeInfo(null, null, null, null); + + // Call + Color color = treeNodeInfo.ForeColor(context); + + // Assert + Assert.AreEqual(Color.FromKnownColor(KnownColor.ControlText), color); + mocks.VerifyAll(); + } + + [Test] + public void ForeColor_FailureMechanismIsNotRelevant_ReturnsGrayText() + { + // Setup + var mocks = new MockRepository(); + var failureMechanism = mocks.Stub(); + var assessmentSection = mocks.Stub(); + mocks.ReplayAll(); + + failureMechanism.IsRelevant = false; + + var context = new TestFailureMechanismContext(failureMechanism, assessmentSection); + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateFailureMechanismContextTreeNodeInfo(null, null, null, null); + + // Call + Color color = treeNodeInfo.ForeColor(context); + + // Assert + Assert.AreEqual(Color.FromKnownColor(KnownColor.GrayText), color); + mocks.VerifyAll(); + } + + [Test] + public void ChildNodeObjects_FailureMechanismIsRelevant_ReturnResultFromConstructorMethod() + { + // Setup + var mocks = new MockRepository(); + var failureMechanism = mocks.Stub(); + var assessmentSection = mocks.Stub(); + + mocks.ReplayAll(); + + failureMechanism.IsRelevant = true; + + var resultIsRelevant = new[] + { + new object(), + 1.1 + }; + + var resultIsNotRelevant = new[] + { + 2.2, + new object() + }; + + var context = new TestFailureMechanismContext(failureMechanism, assessmentSection); + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateFailureMechanismContextTreeNodeInfo(mechanismContext => resultIsRelevant, mechanismContext => resultIsNotRelevant, null, null); + + // Call + object[] children = treeNodeInfo.ChildNodeObjects(context); + + // Assert + CollectionAssert.AreEqual(resultIsRelevant, children); + + mocks.VerifyAll(); + } + + [Test] + public void ChildNodeObjects_FailureMechanismIsNotRelevant_ReturnResultFromConstructorMethod() + { + // Setup + var mocks = new MockRepository(); + var failureMechanism = mocks.Stub(); + var assessmentSection = mocks.Stub(); + + mocks.ReplayAll(); + + failureMechanism.IsRelevant = false; + + var resultIsRelevant = new[] + { + new object(), + 1.1 + }; + + var resultIsNotRelevant = new[] + { + 2.2, + new object() + }; + + var context = new TestFailureMechanismContext(failureMechanism, assessmentSection); + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateFailureMechanismContextTreeNodeInfo(mechanismContext => resultIsRelevant, mechanismContext => resultIsNotRelevant, null, null); + + // Call + object[] children = treeNodeInfo.ChildNodeObjects(context); + + // Assert + CollectionAssert.AreEqual(resultIsNotRelevant, children); + + mocks.VerifyAll(); + } + + [Test] + public void ContextMenuStrip_FailureMechanismIsRelevant_ReturnResultFromConstructorMethod() + { + // Setup + using (var treeView = new TreeViewControl()) + using (var contextMenuStripRelevant = new ContextMenuStrip()) + using (var contextMenuStripNotRelevant = new ContextMenuStrip()) + { + var mocks = new MockRepository(); + var failureMechanism = mocks.Stub(); + var assessmentSection = mocks.Stub(); + + mocks.ReplayAll(); + + failureMechanism.IsRelevant = true; + + var context = new TestFailureMechanismContext(failureMechanism, assessmentSection); + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateFailureMechanismContextTreeNodeInfo(null, null, + (mechanismContext, parent, treeViewControl) => + { + Assert.AreEqual(context, mechanismContext); + Assert.AreEqual(assessmentSection, parent); + Assert.AreEqual(treeView, treeViewControl); + + return contextMenuStripRelevant; + }, + (mechanismContext, parent, treeViewControl) => + { + Assert.AreEqual(context, mechanismContext); + Assert.AreEqual(assessmentSection, parent); + Assert.AreEqual(treeView, treeViewControl); + + return contextMenuStripNotRelevant; + }); + + // Call + ContextMenuStrip result = treeNodeInfo.ContextMenuStrip(context, assessmentSection, treeView); + + // Assert + Assert.AreSame(contextMenuStripRelevant, result); + mocks.VerifyAll(); + } + } + + [Test] + public void ContextMenuStrip_FailureMechanismIsNotRelevant_ReturnResultFromConstructorMethod() + { + // Setup + using (var treeView = new TreeViewControl()) + using (var contextMenuStripRelevant = new ContextMenuStrip()) + using (var contextMenuStripNotRelevant = new ContextMenuStrip()) + { + var mocks = new MockRepository(); + var failureMechanism = mocks.Stub(); + var assessmentSection = mocks.Stub(); + + mocks.ReplayAll(); + + failureMechanism.IsRelevant = false; + + var context = new TestFailureMechanismContext(failureMechanism, assessmentSection); + var treeNodeInfo = RingtoetsTreeNodeInfoFactory.CreateFailureMechanismContextTreeNodeInfo(null, null, + (mechanismContext, parent, treeViewControl) => + { + Assert.AreEqual(context, mechanismContext); + Assert.AreEqual(assessmentSection, parent); + Assert.AreEqual(treeView, treeViewControl); + + return contextMenuStripRelevant; + }, + (mechanismContext, parent, treeViewControl) => + { + Assert.AreEqual(context, mechanismContext); + Assert.AreEqual(assessmentSection, parent); + Assert.AreEqual(treeView, treeViewControl); + + return contextMenuStripNotRelevant; + }); + + // Call + ContextMenuStrip result = treeNodeInfo.ContextMenuStrip(context, assessmentSection, treeView); + + // Assert + Assert.AreSame(contextMenuStripNotRelevant, result); + mocks.VerifyAll(); + } + } + + # endregion + + # region Nested types + + private class TestCalculationGroupContext : Observable, ICalculationContext + { + public TestCalculationGroupContext(CalculationGroup wrappedData, IFailureMechanism failureMechanism) + { + WrappedData = wrappedData; + FailureMechanism = failureMechanism; + } + + public CalculationGroup WrappedData { get; private set; } + + public IFailureMechanism FailureMechanism { get; private set; } + } + + private class TestCalculationContext : Observable, ICalculationContext + { + public TestCalculationContext(TestCalculation wrappedData, IFailureMechanism failureMechanism) + { + WrappedData = wrappedData; + FailureMechanism = failureMechanism; + } + + public TestCalculation WrappedData { get; private set; } + + public IFailureMechanism FailureMechanism { get; private set; } + } + + private class TestCalculation : Observable, ICalculation + { + public TestCalculation() + { + Name = "Nieuwe berekening"; + } + + public string Name { get; set; } + + public string Comments { get; set; } + + public bool HasOutput + { + get + { + return false; + } + } + + public void ClearOutput() {} + + public void ClearHydraulicBoundaryLocation() {} + + public ICalculationInput GetObservableInput() + { + return null; + } + } + + private class TestFailureMechanismContext : FailureMechanismContext + { + public TestFailureMechanismContext(IFailureMechanism wrappedFailureMechanism, IAssessmentSection parent) : base(wrappedFailureMechanism, parent) { } + } + + /// + /// Type indicator for testing methods on . + /// + public enum DragDropTestMethod + { + /// + /// Indicates . + /// + CanDrop, + + /// + /// Indicates . + /// + CanInsert + } + + /// + /// Type indicator for implementations of to be created in a test. + /// + public enum CalculationItemType + { + /// + /// Indicates . + /// + Calculation, + + /// + /// Indicates . + /// + Group + } + + # endregion + } +} \ No newline at end of file Index: Ringtoets/GrassCoverErosionInwards/src/Ringtoets.GrassCoverErosionInwards.Plugin/GrassCoverErosionInwardsGuiPlugin.cs =================================================================== diff -u -rfa493fef4f3f244664392c28896afb2052596898 -r36b6f1f7c1ddf585689512eb61256d41a1e0ca64 --- Ringtoets/GrassCoverErosionInwards/src/Ringtoets.GrassCoverErosionInwards.Plugin/GrassCoverErosionInwardsGuiPlugin.cs (.../GrassCoverErosionInwardsGuiPlugin.cs) (revision fa493fef4f3f244664392c28896afb2052596898) +++ Ringtoets/GrassCoverErosionInwards/src/Ringtoets.GrassCoverErosionInwards.Plugin/GrassCoverErosionInwardsGuiPlugin.cs (.../GrassCoverErosionInwardsGuiPlugin.cs) (revision 36b6f1f7c1ddf585689512eb61256d41a1e0ca64) @@ -68,18 +68,18 @@ public override IEnumerable GetTreeNodeInfos() { - yield return CalculationTreeNodeInfoFactory.CreateFailureMechanismContextTreeNodeInfo( + yield return RingtoetsTreeNodeInfoFactory.CreateFailureMechanismContextTreeNodeInfo( FailureMechanismEnabledChildNodeObjects, FailureMechanismDisabledChildNodeObjects, FailureMechanismEnabledContextMenuStrip, FailureMechanismDisabledContextMenuStrip); - yield return CalculationTreeNodeInfoFactory.CreateCalculationGroupContextTreeNodeInfo( + yield return RingtoetsTreeNodeInfoFactory.CreateCalculationGroupContextTreeNodeInfo( CalculationGroupContextChildNodeObjects, CalculationGroupContextContextMenuStrip, CalculationGroupContextOnNodeRemoved); - yield return CalculationTreeNodeInfoFactory.CreateCalculationContextTreeNodeInfo( + yield return RingtoetsTreeNodeInfoFactory.CreateCalculationContextTreeNodeInfo( GrassCoverErosionInwardsFormsResources.CalculationIcon, CalculationContextChildNodeObjects, CalculationContextContextmenuStrip, @@ -263,7 +263,7 @@ { var builder = Gui.Get(grassCoverErosionInwardsFailureMechanismContext, treeViewControl); - ContextMenuItemFactory.AddDisabledChangeRelevancyItem(builder, grassCoverErosionInwardsFailureMechanismContext); + RingtoetsContextMenuItemFactory.AddDisabledChangeRelevancyItem(builder, grassCoverErosionInwardsFailureMechanismContext); return builder.AddSeparator() .AddExpandAllItem() @@ -327,11 +327,11 @@ .AddSeparator(); } - ContextMenuItemFactory.AddCreateCalculationGroupItem(builder, group); - ContextMenuItemFactory.AddCreateCalculationItem(builder, nodeData, AddCalculation); + RingtoetsContextMenuItemFactory.AddCreateCalculationGroupItem(builder, group); + RingtoetsContextMenuItemFactory.AddCreateCalculationItem(builder, nodeData, AddCalculation); builder.AddSeparator(); - ContextMenuItemFactory.AddPerformAllCalculationsInGroupItem(builder, group, nodeData, CalculateAll); - ContextMenuItemFactory.AddClearAllCalculationOutputInGroupItem(builder, group); + RingtoetsContextMenuItemFactory.AddPerformAllCalculationsInGroupItem(builder, group, nodeData, CalculateAll); + RingtoetsContextMenuItemFactory.AddClearAllCalculationOutputInGroupItem(builder, group); builder.AddSeparator(); if (isNestedGroup) @@ -399,12 +399,12 @@ GrassCoverErosionInwardsCalculation calculation = nodeData.WrappedData; - ContextMenuItemFactory.AddPerformCalculationItem( + RingtoetsContextMenuItemFactory.AddPerformCalculationItem( builder, calculation, nodeData, PerformCalculation); - ContextMenuItemFactory.AddClearCalculationOutputItem(builder, calculation); + RingtoetsContextMenuItemFactory.AddClearCalculationOutputItem(builder, calculation); builder.AddSeparator(); return builder Index: Ringtoets/Integration/src/Ringtoets.Integration.Plugin/RingtoetsGuiPlugin.cs =================================================================== diff -u -rb47c41dd3741ada477388e6c8a9224ecb66291e7 -r36b6f1f7c1ddf585689512eb61256d41a1e0ca64 --- Ringtoets/Integration/src/Ringtoets.Integration.Plugin/RingtoetsGuiPlugin.cs (.../RingtoetsGuiPlugin.cs) (revision b47c41dd3741ada477388e6c8a9224ecb66291e7) +++ Ringtoets/Integration/src/Ringtoets.Integration.Plugin/RingtoetsGuiPlugin.cs (.../RingtoetsGuiPlugin.cs) (revision 36b6f1f7c1ddf585689512eb61256d41a1e0ca64) @@ -192,7 +192,7 @@ Gui.Get(nodeData, treeViewControl).AddImportItem().Build() }; - yield return CalculationTreeNodeInfoFactory.CreateFailureMechanismContextTreeNodeInfo( + yield return RingtoetsTreeNodeInfoFactory.CreateFailureMechanismContextTreeNodeInfo( FailureMechanismPlaceholderEnabledChildNodeObjects, FailureMechanismPlaceholderDisabledChildNodeObjects, FailureMechanismPlaceholderEnabledContextMenuStrip, @@ -561,7 +561,7 @@ { var builder = Gui.Get(nodeData, treeViewControl); - ContextMenuItemFactory.AddDisabledChangeRelevancyItem(builder, nodeData); + RingtoetsContextMenuItemFactory.AddDisabledChangeRelevancyItem(builder, nodeData); return builder.AddSeparator() .AddExpandAllItem() Index: Ringtoets/Piping/src/Ringtoets.Piping.Plugin/PipingGuiPlugin.cs =================================================================== diff -u -rfa493fef4f3f244664392c28896afb2052596898 -r36b6f1f7c1ddf585689512eb61256d41a1e0ca64 --- Ringtoets/Piping/src/Ringtoets.Piping.Plugin/PipingGuiPlugin.cs (.../PipingGuiPlugin.cs) (revision fa493fef4f3f244664392c28896afb2052596898) +++ Ringtoets/Piping/src/Ringtoets.Piping.Plugin/PipingGuiPlugin.cs (.../PipingGuiPlugin.cs) (revision 36b6f1f7c1ddf585689512eb61256d41a1e0ca64) @@ -104,19 +104,19 @@ public override IEnumerable GetTreeNodeInfos() { - yield return CalculationTreeNodeInfoFactory.CreateFailureMechanismContextTreeNodeInfo( + yield return RingtoetsTreeNodeInfoFactory.CreateFailureMechanismContextTreeNodeInfo( FailureMechanismEnabledChildNodeObjects, FailureMechanismDisabledChildNodeObjects, FailureMechanismEnabledContextMenuStrip, FailureMechanismDisabledContextMenuStrip); - yield return CalculationTreeNodeInfoFactory.CreateCalculationContextTreeNodeInfo( + yield return RingtoetsTreeNodeInfoFactory.CreateCalculationContextTreeNodeInfo( PipingFormsResources.PipingIcon, PipingCalculationContextChildNodeObjects, PipingCalculationContextContextMenuStrip, PipingCalculationContextOnNodeRemoved); - yield return CalculationTreeNodeInfoFactory.CreateCalculationGroupContextTreeNodeInfo( + yield return RingtoetsTreeNodeInfoFactory.CreateCalculationGroupContextTreeNodeInfo( PipingCalculationGroupContextChildNodeObjects, PipingCalculationGroupContextContextMenuStrip, PipingCalculationGroupContextOnNodeRemoved); @@ -324,7 +324,7 @@ { var builder = Gui.Get(pipingFailureMechanismContext, treeViewControl); - ContextMenuItemFactory.AddDisabledChangeRelevancyItem(builder, pipingFailureMechanismContext); + RingtoetsContextMenuItemFactory.AddDisabledChangeRelevancyItem(builder, pipingFailureMechanismContext); return builder.AddSeparator() .AddExpandAllItem() @@ -453,8 +453,8 @@ (o, args) => { PipingCalculationService.Validate(calculation); }); builder.AddCustomItem(validateItem); - ContextMenuItemFactory.AddPerformCalculationItem(builder, calculation, nodeData, PerformCalculation); - ContextMenuItemFactory.AddClearCalculationOutputItem(builder, calculation); + RingtoetsContextMenuItemFactory.AddPerformCalculationItem(builder, calculation, nodeData, PerformCalculation); + RingtoetsContextMenuItemFactory.AddClearCalculationOutputItem(builder, calculation); builder.AddSeparator(); return builder.AddRenameItem() @@ -571,12 +571,12 @@ .AddSeparator(); } - ContextMenuItemFactory.AddCreateCalculationGroupItem(builder, group); - ContextMenuItemFactory.AddCreateCalculationItem(builder, nodeData, AddCalculationScenario); + RingtoetsContextMenuItemFactory.AddCreateCalculationGroupItem(builder, group); + RingtoetsContextMenuItemFactory.AddCreateCalculationItem(builder, nodeData, AddCalculationScenario); builder.AddSeparator(); builder.AddCustomItem(validateAllItem); - ContextMenuItemFactory.AddPerformAllCalculationsInGroupItem(builder, group, nodeData, CalculateAll); - ContextMenuItemFactory.AddClearAllCalculationOutputInGroupItem(builder, group); + RingtoetsContextMenuItemFactory.AddPerformAllCalculationsInGroupItem(builder, group, nodeData, CalculateAll); + RingtoetsContextMenuItemFactory.AddClearAllCalculationOutputInGroupItem(builder, group); builder.AddSeparator(); if (isNestedGroup)