Index: Ringtoets/Piping/src/Ringtoets.Piping.Data/PipingCalculationGroup.cs =================================================================== diff -u -r6bcbd610ececdc293a8883b50448f369e1fa4a25 -r0b1b3f19d5bcb07e6d1edcee520a34742a9da8a8 --- Ringtoets/Piping/src/Ringtoets.Piping.Data/PipingCalculationGroup.cs (.../PipingCalculationGroup.cs) (revision 6bcbd610ececdc293a8883b50448f369e1fa4a25) +++ Ringtoets/Piping/src/Ringtoets.Piping.Data/PipingCalculationGroup.cs (.../PipingCalculationGroup.cs) (revision 0b1b3f19d5bcb07e6d1edcee520a34742a9da8a8) @@ -39,7 +39,7 @@ /// /// Gets the children that define this group. /// - public ICollection Children { get; private set; } + public IList Children { get; private set; } /// /// Gets or sets the name of this calculation grouping object. Index: Ringtoets/Piping/src/Ringtoets.Piping.Forms/NodePresenters/PipingCalculationGroupContextNodePresenter.cs =================================================================== diff -u -r3966c8176854557199325b0465f0c6a1c9225f38 -r0b1b3f19d5bcb07e6d1edcee520a34742a9da8a8 --- Ringtoets/Piping/src/Ringtoets.Piping.Forms/NodePresenters/PipingCalculationGroupContextNodePresenter.cs (.../PipingCalculationGroupContextNodePresenter.cs) (revision 3966c8176854557199325b0465f0c6a1c9225f38) +++ Ringtoets/Piping/src/Ringtoets.Piping.Forms/NodePresenters/PipingCalculationGroupContextNodePresenter.cs (.../PipingCalculationGroupContextNodePresenter.cs) (revision 0b1b3f19d5bcb07e6d1edcee520a34742a9da8a8) @@ -4,6 +4,7 @@ using System.Drawing; using System.Linq; using System.Windows.Forms; + using Core.Common.Base.Service; using Core.Common.Controls; using Core.Common.Controls.Swf.TreeViewControls; @@ -16,6 +17,7 @@ using Ringtoets.Piping.Data.Properties; using Ringtoets.Piping.Forms.PresentationObjects; using Ringtoets.Piping.Service; + using RingtoetsFormsResources = Ringtoets.Common.Forms.Properties.Resources; using PipingFormsResources = Ringtoets.Piping.Forms.Properties.Resources; @@ -33,7 +35,7 @@ /// The /// to use for building a . /// Thrown when no was provided. - public PipingCalculationGroupContextNodePresenter(IContextMenuBuilderProvider contextMenuBuilderProvider) : base(contextMenuBuilderProvider) { } + public PipingCalculationGroupContextNodePresenter(IContextMenuBuilderProvider contextMenuBuilderProvider) : base(contextMenuBuilderProvider) {} /// /// Injection points for a method to cause an to be scheduled for execution. @@ -42,41 +44,19 @@ public override DragOperations CanDrop(object item, ITreeNode sourceNode, ITreeNode targetNode, DragOperations validOperations) { - var targetGroup = ((PipingCalculationGroupContext)targetNode.Tag).WrappedData; - - IPipingCalculationItem pipingCalculationItem = GetAsIPipingCalculationItem(item); - if (pipingCalculationItem != null && !targetGroup.Children.Contains(pipingCalculationItem) && NodesHaveSameParentFailureMechanism(sourceNode, targetNode)) + if (GetAsIPipingCalculationItem(item) != null && NodesHaveSameParentFailureMechanism(sourceNode, targetNode)) { return validOperations; } return base.CanDrop(item, sourceNode, targetNode, validOperations); } - private bool NodesHaveSameParentFailureMechanism(ITreeNode sourceNode, ITreeNode targetNode) + public override bool CanInsert(object item, ITreeNode sourceNode, ITreeNode targetNode) { - var sourceFailureMechanism = GetParentFailureMechanism(sourceNode); - var targetFailureMechanism = GetParentFailureMechanism(targetNode); - - return ReferenceEquals(sourceFailureMechanism, targetFailureMechanism); + return GetAsIPipingCalculationItem(item) != null && NodesHaveSameParentFailureMechanism(sourceNode, targetNode); } - private static PipingFailureMechanism GetParentFailureMechanism(ITreeNode sourceNode) - { - PipingFailureMechanism sourceFailureMechanism; - var node = sourceNode; - while ((sourceFailureMechanism = node.Tag as PipingFailureMechanism) == null) - { - // No parent found, go search higher up hierarchy! - node = node.Parent; - if (node == null) - { - break; - } - } - return sourceFailureMechanism; - } - public override bool CanRenameNode(ITreeNode node) { return node.Parent == null || !(node.Parent.Tag is PipingFailureMechanism); @@ -205,17 +185,6 @@ .Build(); } - private void SelectNewlyAddedItemInTreeView(ITreeNode node) - { - // Expand parent of 'newItem' to ensure its selected state is visible. - if (!node.IsExpanded) - { - node.Expand(); - } - ITreeNode newlyAppendedNodeForNewItem = node.Nodes.Last(); - TreeView.SelectedNode = newlyAppendedNodeForNewItem; - } - protected override IEnumerable GetChildNodeObjects(PipingCalculationGroupContext nodeData) { foreach (IPipingCalculationItem item in nodeData.WrappedData.Children) @@ -257,18 +226,26 @@ var originalOwnerContext = itemParent as PipingCalculationGroupContext; if (pipingCalculationItem != null && originalOwnerContext != null) { + var isMoveWithinSameContainer = ReferenceEquals(target, originalOwnerContext); + var recordedNodeState = new TreeNodeExpandCollapseState(TreeView.GetNodeByTag(item)); - string uniqueName = GetUniqueNameForCalculationItem(pipingCalculationItem, target.WrappedData); bool renamed = false; - if (!pipingCalculationItem.Name.Equals(uniqueName)) + if (!isMoveWithinSameContainer) { - renamed = TryRenameTo(pipingCalculationItem, uniqueName); + string uniqueName = NamingHelper.GetUniqueName(target.WrappedData.Children, pipingCalculationItem.Name, pci => pci.Name); + if (!pipingCalculationItem.Name.Equals(uniqueName)) + { + renamed = TryRenameTo(pipingCalculationItem, uniqueName); + } } originalOwnerContext.WrappedData.Children.Remove(pipingCalculationItem); - target.WrappedData.Children.Add(pipingCalculationItem); + target.WrappedData.Children.Insert(position, pipingCalculationItem); originalOwnerContext.NotifyObservers(); - target.NotifyObservers(); + if (!isMoveWithinSameContainer) + { + target.NotifyObservers(); + } // Expand parent of 'draggedNode' to ensure its selected state is visible. ITreeNode draggedNode = TreeView.GetNodeByTag(item); @@ -290,16 +267,41 @@ } } - private static string GetUniqueNameForCalculationItem(IPipingCalculationItem pipingCalculationItem, PipingCalculationGroup parentGroup) + private bool NodesHaveSameParentFailureMechanism(ITreeNode sourceNode, ITreeNode targetNode) { - string itemBaseName = pipingCalculationItem is PipingCalculation ? - Resources.PipingCalculation_DefaultName : - (pipingCalculationItem is PipingCalculationGroup ? - Resources.PipingCalculationGroup_DefaultName : - null); - return NamingHelper.GetUniqueName(parentGroup.Children, itemBaseName, pci => pci.Name); + var sourceFailureMechanism = GetParentFailureMechanism(sourceNode); + var targetFailureMechanism = GetParentFailureMechanism(targetNode); + + return ReferenceEquals(sourceFailureMechanism, targetFailureMechanism); } + private static PipingFailureMechanism GetParentFailureMechanism(ITreeNode sourceNode) + { + PipingFailureMechanism sourceFailureMechanism; + var node = sourceNode; + while ((sourceFailureMechanism = node.Tag as PipingFailureMechanism) == null) + { + // No parent found, go search higher up hierarchy! + node = node.Parent; + if (node == null) + { + break; + } + } + return sourceFailureMechanism; + } + + private void SelectNewlyAddedItemInTreeView(ITreeNode node) + { + // Expand parent of 'newItem' to ensure its selected state is visible. + if (!node.IsExpanded) + { + node.Expand(); + } + ITreeNode newlyAppendedNodeForNewItem = node.Nodes.Last(); + TreeView.SelectedNode = newlyAppendedNodeForNewItem; + } + private static bool TryRenameTo(IPipingCalculationItem pipingCalculationItem, string uniqueName) { var calculation = pipingCalculationItem as PipingCalculation; Index: Ringtoets/Piping/test/Ringtoets.Piping.Forms.Test/NodePresenters/PipingCalculationGroupContextNodePresenterTest.cs =================================================================== diff -u -r3966c8176854557199325b0465f0c6a1c9225f38 -r0b1b3f19d5bcb07e6d1edcee520a34742a9da8a8 --- Ringtoets/Piping/test/Ringtoets.Piping.Forms.Test/NodePresenters/PipingCalculationGroupContextNodePresenterTest.cs (.../PipingCalculationGroupContextNodePresenterTest.cs) (revision 3966c8176854557199325b0465f0c6a1c9225f38) +++ Ringtoets/Piping/test/Ringtoets.Piping.Forms.Test/NodePresenters/PipingCalculationGroupContextNodePresenterTest.cs (.../PipingCalculationGroupContextNodePresenterTest.cs) (revision 0b1b3f19d5bcb07e6d1edcee520a34742a9da8a8) @@ -176,19 +176,46 @@ } [Test] - public void CanDrop_DraggingPipingCalculationContextOntoGroupNotContainingCalculation_ReturnMove() + [Combinatorial] + public void CanDropOrCanInsert_DraggingPipingCalculationItemContextOntoGroupNotContainingItem_ReturnMoveOrTrue( + [Values(DragDropTestMethod.CanDrop, DragDropTestMethod.CanInsert)] DragDropTestMethod methodToTest, + [Values(PipingCalculationItemType.Calculation, PipingCalculationItemType.Group)] PipingCalculationItemType draggedItemType) { // Setup - var calculation = new PipingCalculation(); - var calculationContext = new PipingCalculationContext(calculation, - Enumerable.Empty(), - Enumerable.Empty()); + IPipingCalculationItem draggedItem = null; + object draggedItemContext = null; + + #region Setup data objects related to dragged IPipingCalculationItem: + + switch (draggedItemType) + { + case PipingCalculationItemType.Calculation: + var calculation = new PipingCalculation(); + draggedItem = calculation; + draggedItemContext = new PipingCalculationContext(calculation, + Enumerable.Empty(), + Enumerable.Empty()); + break; + case PipingCalculationItemType.Group: + var group = new PipingCalculationGroup(); + draggedItem = group; + draggedItemContext = new PipingCalculationGroupContext(group, + Enumerable.Empty(), + Enumerable.Empty()); + break; + default: + Assert.Fail(methodToTest + " not supported."); + break; + } + + #endregion + var targetGroup = new PipingCalculationGroup(); var targetGroupContext = new PipingCalculationGroupContext(targetGroup, Enumerable.Empty(), Enumerable.Empty()); var failureMechanism = new PipingFailureMechanism(); - failureMechanism.CalculationsGroup.Children.Add(calculation); + failureMechanism.CalculationsGroup.Children.Add(draggedItem); failureMechanism.CalculationsGroup.Children.Add(targetGroup); #region Mock node tree for source and target in same failure mechanism @@ -201,7 +228,7 @@ failureMechanismGroupNode.Expect(n => n.Parent).Return(failureMechanismNode).Repeat.AtLeastOnce(); var calculationNode = mockRepository.Stub(); - calculationNode.Tag = calculationContext; + calculationNode.Tag = draggedItemContext; calculationNode.Expect(n => n.Parent).Return(failureMechanismGroupNode).Repeat.AtLeastOnce(); var targetGroupNode = mockRepository.Stub(); @@ -214,77 +241,78 @@ mockRepository.ReplayAll(); - // Precondition: - CollectionAssert.DoesNotContain(targetGroup.Children, calculation, - "It doesn't make sense to allow dragging onto a group that already contains that node as direct child."); - var nodePresenter = new PipingCalculationGroupContextNodePresenter(contextMenuBuilderProviderMock); - // Call - DragOperations supportedOperations = nodePresenter.CanDrop(calculationContext, calculationNode, targetGroupNode, DragOperations.Move); + switch (methodToTest) + { + case DragDropTestMethod.CanDrop: + // Call + DragOperations supportedOperations = nodePresenter.CanDrop(draggedItemContext, calculationNode, targetGroupNode, DragOperations.Move); - // Assert - Assert.AreEqual(DragOperations.Move, supportedOperations); + // Assert + Assert.AreEqual(DragOperations.Move, supportedOperations); + break; + case DragDropTestMethod.CanInsert: + // Call + bool canInsert = nodePresenter.CanInsert(draggedItemContext, calculationNode, targetGroupNode); + + // Assert + Assert.IsTrue(canInsert); + break; + default: + Assert.Fail(methodToTest + " not supported."); + break; + } mockRepository.ReplayAll(); } [Test] - public void CanDrop_DraggingPipingCalculationContextOntoGroupContainingCalculation_ReturnNone() + [Combinatorial] + public void CanDropOrCanInsert_DraggingPipingCalculationItemContextOntoGroupNotContainingItemButFromOtherFailureMechanism_ReturnNoneOrFalse( + [Values(DragDropTestMethod.CanDrop, DragDropTestMethod.CanInsert)] DragDropTestMethod methodToTest, + [Values(PipingCalculationItemType.Calculation, PipingCalculationItemType.Group)] PipingCalculationItemType draggedItemType) { // Setup - var calculation = new PipingCalculation(); - var calculationContext = new PipingCalculationContext(calculation, - Enumerable.Empty(), - Enumerable.Empty()); - var targetGroup = new PipingCalculationGroup(); - targetGroup.Children.Add(calculation); - var targetGroupContext = new PipingCalculationGroupContext(targetGroup, - Enumerable.Empty(), - Enumerable.Empty()); + IPipingCalculationItem draggedItem = null; + object draggedItemContext = null; - var calculationNode = mockRepository.Stub(); - calculationNode.Tag = calculationContext; + #region Setup data objects related to dragged IPipingCalculationItem: - var groupNode = mockRepository.Stub(); - groupNode.Tag = targetGroupContext; + switch (draggedItemType) + { + case PipingCalculationItemType.Calculation: + var calculation = new PipingCalculation(); + draggedItem = calculation; + draggedItemContext = new PipingCalculationContext(calculation, + Enumerable.Empty(), + Enumerable.Empty()); + break; + case PipingCalculationItemType.Group: + var group = new PipingCalculationGroup(); + draggedItem = group; + draggedItemContext = new PipingCalculationGroupContext(group, + Enumerable.Empty(), + Enumerable.Empty()); + break; + default: + Assert.Fail(methodToTest + " not supported."); + break; + } - var contextMenuBuilderProviderMock = mockRepository.StrictMock(); - mockRepository.ReplayAll(); - - // Precondition: - CollectionAssert.Contains(targetGroup.Children, calculation, - "It doesn't make sense to allow dragging onto a group that already contains that node as direct child."); - - var nodePresenter = new PipingCalculationGroupContextNodePresenter(contextMenuBuilderProviderMock); - - // Call - DragOperations supportedOperations = nodePresenter.CanDrop(calculationContext, calculationNode, groupNode, DragOperations.Move); - - // Assert - Assert.AreEqual(DragOperations.None, supportedOperations); - mockRepository.ReplayAll(); - } - - [Test] - public void CanDrop_DraggingPipingCalculationContextOntoGroupNotContainingCalculationButFromOtherFailureMechanism_ReturnNone() - { - // Setup - var calculation = new PipingCalculation(); - var calculationContext = new PipingCalculationContext(calculation, - Enumerable.Empty(), - Enumerable.Empty()); var sourceFailureMechanism = new PipingFailureMechanism(); - sourceFailureMechanism.CalculationsGroup.Children.Add(calculation); + sourceFailureMechanism.CalculationsGroup.Children.Add(draggedItem); + #endregion + var targetGroup = new PipingCalculationGroup(); var targetGroupContext = new PipingCalculationGroupContext(targetGroup, Enumerable.Empty(), Enumerable.Empty()); var targetFailureMechanism = new PipingFailureMechanism(); targetFailureMechanism.CalculationsGroup.Children.Add(targetGroup); - #region Mock node tree for source PipingCalculation + #region Mock node tree for source IPipingCalculationItem var sourceFailureMechanismNode = mockRepository.Stub(); sourceFailureMechanismNode.Tag = sourceFailureMechanism; @@ -294,7 +322,7 @@ sourceFailureMechanismGroupNode.Expect(n => n.Parent).Return(sourceFailureMechanismNode).Repeat.AtLeastOnce(); var calculationNode = mockRepository.Stub(); - calculationNode.Tag = calculationContext; + calculationNode.Tag = draggedItemContext; calculationNode.Expect(n => n.Parent).Return(sourceFailureMechanismGroupNode).Repeat.AtLeastOnce(); #endregion @@ -318,189 +346,63 @@ mockRepository.ReplayAll(); - // Precondition: - CollectionAssert.DoesNotContain(targetGroup.Children, calculation, - "It doesn't make sense to allow dragging onto a group that already contains that node as direct child."); - var nodePresenter = new PipingCalculationGroupContextNodePresenter(contextMenuBuilderProviderMock); - // Call - DragOperations supportedOperations = nodePresenter.CanDrop(calculationContext, calculationNode, groupNode, DragOperations.Move); + switch (methodToTest) + { + case DragDropTestMethod.CanDrop: + // Call + DragOperations supportedOperations = nodePresenter.CanDrop(draggedItemContext, calculationNode, groupNode, DragOperations.Move); - // Assert - Assert.AreEqual(DragOperations.None, supportedOperations); - mockRepository.ReplayAll(); - } + // Assert + Assert.AreEqual(DragOperations.None, supportedOperations); + break; + case DragDropTestMethod.CanInsert: + // Call + bool canInsert = nodePresenter.CanInsert(draggedItemContext, calculationNode, groupNode); - [Test] - public void CanDrop_DraggingPipingCalculationGroupContextOntoGroupNotContainingGroup_ReturnMove() - { - // Setup - var group = new PipingCalculationGroup(); - var groupContext = new PipingCalculationGroupContext(group, - Enumerable.Empty(), - Enumerable.Empty()); - var targetGroup = new PipingCalculationGroup(); - var targetGroupContext = new PipingCalculationGroupContext(targetGroup, - Enumerable.Empty(), - Enumerable.Empty()); - - var failureMechanism = new PipingFailureMechanism(); - failureMechanism.CalculationsGroup.Children.Add(group); - failureMechanism.CalculationsGroup.Children.Add(targetGroup); - - #region Mock node tree for groups in same failure mechanism - - var failureMechanismNode = mockRepository.Stub(); - failureMechanismNode.Tag = failureMechanism; - - var failureMechanismGroupNode = mockRepository.Stub(); - failureMechanismGroupNode.Tag = failureMechanism.CalculationsGroup; - failureMechanismGroupNode.Expect(n => n.Parent).Return(failureMechanismNode).Repeat.AtLeastOnce(); - - var groupNode = mockRepository.Stub(); - groupNode.Tag = group; - groupNode.Expect(n => n.Parent).Return(failureMechanismGroupNode).Repeat.AtLeastOnce(); - - var targetGroupNode = mockRepository.Stub(); - targetGroupNode.Tag = targetGroupContext; - targetGroupNode.Expect(n => n.Parent).Return(failureMechanismGroupNode).Repeat.AtLeastOnce(); - - #endregion - - - var contextMenuBuilderProviderMock = mockRepository.StrictMock(); - + // Assert + Assert.IsFalse(canInsert); + break; + default: + Assert.Fail(methodToTest + " not supported."); + break; + } mockRepository.ReplayAll(); - - // Precondition: - CollectionAssert.DoesNotContain(targetGroup.Children, group, - "It doesn't make sense to allow dragging onto a group that already contains that node as direct child."); - - var nodePresenter = new PipingCalculationGroupContextNodePresenter(contextMenuBuilderProviderMock); - - // Call - DragOperations supportedOperations = nodePresenter.CanDrop(groupContext, groupNode, targetGroupNode, DragOperations.Move); - - // Assert - Assert.AreEqual(DragOperations.Move, supportedOperations); - mockRepository.ReplayAll(); } [Test] - public void CanDrop_DraggingPipingCalculationGroupContextOntoGroupContainingGroup_ReturnNone() + [Combinatorial] + public void OnDragDrop_DraggingPipingCalculationItemContextOntoGroupEnd_MoveCalculationItemInstanceToNewGroup( + [Values(PipingCalculationItemType.Calculation, PipingCalculationItemType.Group)] PipingCalculationItemType draggedItemType) { // Setup - var group = new PipingCalculation(); - var groupContext = new PipingCalculationContext(group, - Enumerable.Empty(), - Enumerable.Empty()); - var targetGroup = new PipingCalculationGroup(); - targetGroup.Children.Add(group); - var targetGroupContext = new PipingCalculationGroupContext(targetGroup, - Enumerable.Empty(), - Enumerable.Empty()); + IPipingCalculationItem draggedItem = null; + object draggedItemContext = null; - var groupNode = mockRepository.Stub(); - groupNode.Tag = groupContext; - - var targetGroupNode = mockRepository.Stub(); - targetGroupNode.Tag = targetGroupContext; - - var contextMenuBuilderProviderMock = mockRepository.StrictMock(); - - mockRepository.ReplayAll(); - - // Precondition: - CollectionAssert.Contains(targetGroup.Children, group, - "It doesn't make sense to allow dragging onto a group that already contains that node as direct child."); - - var nodePresenter = new PipingCalculationGroupContextNodePresenter(contextMenuBuilderProviderMock); - - // Call - DragOperations supportedOperations = nodePresenter.CanDrop(groupContext, groupNode, targetGroupNode, DragOperations.Move); - - // Assert - Assert.AreEqual(DragOperations.None, supportedOperations); - mockRepository.ReplayAll(); - } - - [Test] - public void CanDrop_DraggingPipingCalculationGroupContextOntoGroupNotContainingGroupButFromOtherFailureMechanism_ReturnNone() - { - // Setup - var draggedGroup = new PipingCalculation(); - var draggedGroupContext = new PipingCalculationContext(draggedGroup, - Enumerable.Empty(), - Enumerable.Empty()); - var sourceFailureMechanism = new PipingFailureMechanism(); - sourceFailureMechanism.CalculationsGroup.Children.Add(draggedGroup); - - var targetGroup = new PipingCalculationGroup(); - var targetGroupContext = new PipingCalculationGroupContext(targetGroup, - Enumerable.Empty(), - Enumerable.Empty()); - var targetFailureMechanism = new PipingFailureMechanism(); - targetFailureMechanism.CalculationsGroup.Children.Add(targetGroup); - - #region Mock node tree for source PipingCalculation - - var sourceFailureMechanismNode = mockRepository.Stub(); - sourceFailureMechanismNode.Tag = sourceFailureMechanism; - - var sourceFailureMechanismGroupNode = mockRepository.Stub(); - sourceFailureMechanismGroupNode.Tag = sourceFailureMechanism.CalculationsGroup; - sourceFailureMechanismGroupNode.Expect(n => n.Parent).Return(sourceFailureMechanismNode).Repeat.AtLeastOnce(); - - var draggedGroupNode = mockRepository.Stub(); - draggedGroupNode.Tag = draggedGroupContext; - draggedGroupNode.Expect(n => n.Parent).Return(sourceFailureMechanismGroupNode).Repeat.AtLeastOnce(); - - #endregion - - #region Mock node tree for target PipingCalculationGroup - - var targetFailureMechanismNode = mockRepository.Stub(); - targetFailureMechanismNode.Tag = targetFailureMechanism; - - var targetFailureMechanismGroupNode = mockRepository.Stub(); - targetFailureMechanismGroupNode.Tag = targetFailureMechanism.CalculationsGroup; - targetFailureMechanismGroupNode.Expect(n => n.Parent).Return(targetFailureMechanismNode).Repeat.AtLeastOnce(); - - var targetGroupNode = mockRepository.Stub(); - targetGroupNode.Tag = targetGroupContext; - targetGroupNode.Expect(n => n.Parent).Return(targetFailureMechanismGroupNode).Repeat.AtLeastOnce(); - - #endregion - - var contextMenuBuilderProviderMock = mockRepository.StrictMock(); - - mockRepository.ReplayAll(); - - // Precondition: - CollectionAssert.DoesNotContain(targetGroup.Children, draggedGroup, - "It doesn't make sense to allow dragging onto a group that already contains that node as direct child."); - - var nodePresenter = new PipingCalculationGroupContextNodePresenter(contextMenuBuilderProviderMock); - - // Call - DragOperations supportedOperations = nodePresenter.CanDrop(draggedGroupContext, draggedGroupNode, targetGroupNode, DragOperations.Move); - - // Assert - Assert.AreEqual(DragOperations.None, supportedOperations); - mockRepository.ReplayAll(); - } - - [Test] - public void OnDragDrop_DraggingPipingCalculationContextOntoGroup_MoveCalculationInstanceToNewGroup() - { - // Setup - var calculation = new PipingCalculation(); - var calculationContext = new PipingCalculationContext(calculation, - Enumerable.Empty(), - Enumerable.Empty()); + switch (draggedItemType) + { + case PipingCalculationItemType.Calculation: + var calculation = new PipingCalculation(); + draggedItem = calculation; + draggedItemContext = new PipingCalculationContext(calculation, + Enumerable.Empty(), + Enumerable.Empty()); + break; + case PipingCalculationItemType.Group: + var group = new PipingCalculationGroup(); + draggedItem = group; + draggedItemContext = new PipingCalculationGroupContext(group, + Enumerable.Empty(), + Enumerable.Empty()); + break; + default: + Assert.Fail(); + break; + } + var originalOwnerGroup = new PipingCalculationGroup(); - originalOwnerGroup.Children.Add(calculation); + originalOwnerGroup.Children.Add(draggedItem); var originalOwnerGroupContext = new PipingCalculationGroupContext(originalOwnerGroup, Enumerable.Empty(), Enumerable.Empty()); @@ -521,26 +423,26 @@ newOwnerGroupContextNode.Expect(n => n.IsExpanded).Return(false); newOwnerGroupContextNode.Expect(n => n.Expand()); // Must expand new owner, otherwise selecting dragged node could not be visible when parent is collapsed. - var preUpdateCalculationContextNode = mockRepository.Stub(); - preUpdateCalculationContextNode.Tag = calculationContext; - preUpdateCalculationContextNode.Expect(n => n.IsExpanded).Return(false); - preUpdateCalculationContextNode.Stub(n => n.Nodes).Return(new List()); + var preUpdateDraggedItemContextNode = mockRepository.Stub(); + preUpdateDraggedItemContextNode.Tag = draggedItemContext; + preUpdateDraggedItemContextNode.Expect(n => n.IsExpanded).Return(false); + preUpdateDraggedItemContextNode.Stub(n => n.Nodes).Return(new List()); - var postUpdateCalculationContextNode = mockRepository.Stub(); - postUpdateCalculationContextNode.Tag = calculationContext; - postUpdateCalculationContextNode.Expect(n => n.Parent).Return(newOwnerGroupContextNode); - postUpdateCalculationContextNode.Expect(n => n.IsExpanded).Return(true); - postUpdateCalculationContextNode.Expect(n => n.Collapse()); - postUpdateCalculationContextNode.Stub(n => n.Nodes).Return(new List()); + var postUpdateDraggedItemContextNode = mockRepository.Stub(); + postUpdateDraggedItemContextNode.Tag = draggedItemContext; + postUpdateDraggedItemContextNode.Expect(n => n.Parent).Return(newOwnerGroupContextNode); + postUpdateDraggedItemContextNode.Expect(n => n.IsExpanded).Return(true); + postUpdateDraggedItemContextNode.Expect(n => n.Collapse()); + postUpdateDraggedItemContextNode.Stub(n => n.Nodes).Return(new List()); var treeView = mockRepository.Stub(); - treeView.Expect(v => v.GetNodeByTag(calculationContext)).WhenCalled(invocation => + treeView.Expect(v => v.GetNodeByTag(draggedItemContext)).WhenCalled(invocation => { if (updatewasCalled) { - invocation.ReturnValue = postUpdateCalculationContextNode; + invocation.ReturnValue = postUpdateDraggedItemContextNode; } - }).Return(preUpdateCalculationContextNode).Repeat.Twice(); + }).Return(preUpdateDraggedItemContextNode).Repeat.Twice(); var contextMenuBuilderProviderMock = mockRepository.StrictMock(); @@ -550,126 +452,160 @@ newOwnerGroup.Attach(newOwnerObserver); // Precondition: - CollectionAssert.Contains(originalOwnerGroup.Children, calculation); - CollectionAssert.DoesNotContain(newOwnerGroup.Children, calculation); + CollectionAssert.Contains(originalOwnerGroup.Children, draggedItem); + CollectionAssert.DoesNotContain(newOwnerGroup.Children, draggedItem); var nodePresenter = new PipingCalculationGroupContextNodePresenter(contextMenuBuilderProviderMock) { TreeView = treeView }; // Call - nodePresenter.OnDragDrop(calculationContext, originalOwnerGroupContext, newOwnerGroupContext, DragOperations.Move, int.MaxValue); + nodePresenter.OnDragDrop(draggedItemContext, originalOwnerGroupContext, newOwnerGroupContext, DragOperations.Move, newOwnerGroup.Children.Count); // Assert - CollectionAssert.DoesNotContain(originalOwnerGroup.Children, calculation); - CollectionAssert.Contains(newOwnerGroup.Children, calculation); - Assert.AreSame(calculation, newOwnerGroup.Children.Last()); + CollectionAssert.DoesNotContain(originalOwnerGroup.Children, draggedItem); + CollectionAssert.Contains(newOwnerGroup.Children, draggedItem); + Assert.AreSame(draggedItem, newOwnerGroup.Children.Last(), + "Dragging node at the end of the target PipingCalculationGroup should put the dragged data at the end of 'newOwnerGroup'."); - Assert.AreSame(postUpdateCalculationContextNode, treeView.SelectedNode); + Assert.AreSame(postUpdateDraggedItemContextNode, treeView.SelectedNode); mockRepository.VerifyAll(); } [Test] - public void OnDragDrop_DraggingPipingCalculationContextOntoGroupWithSameNamedItem_MoveCalculationInstanceToNewGroupAndRename() + [Combinatorial] + public void OnDragDrop_InsertingPipingCalculationItemContextAtDifferentLocationWithingSameGroup_ChangeItemIndexOfCalculationItem( + [Values(PipingCalculationItemType.Calculation, PipingCalculationItemType.Group)] PipingCalculationItemType draggedItemType, + [Values(0, 2)] int newIndex) { // Setup - var calculation = new PipingCalculation(); - var calculationContext = new PipingCalculationContext(calculation, - Enumerable.Empty(), - Enumerable.Empty()); + const string name = "Very cool name"; + IPipingCalculationItem draggedItem = null; + object draggedItemContext = null; + + + switch (draggedItemType) + { + case PipingCalculationItemType.Calculation: + var calculation = new PipingCalculation{ Name = name }; + draggedItem = calculation; + draggedItemContext = new PipingCalculationContext(calculation, + Enumerable.Empty(), + Enumerable.Empty()); + break; + case PipingCalculationItemType.Group: + var group = new PipingCalculationGroup{ Name = name }; + draggedItem = group; + draggedItemContext = new PipingCalculationGroupContext(group, + Enumerable.Empty(), + Enumerable.Empty()); + break; + default: + Assert.Fail(); + break; + } + + var existingItemStub = mockRepository.Stub(); + existingItemStub.Stub(i => i.Name).Return(""); + var originalOwnerGroup = new PipingCalculationGroup(); - originalOwnerGroup.Children.Add(calculation); + originalOwnerGroup.Children.Add(existingItemStub); + originalOwnerGroup.Children.Add(draggedItem); + originalOwnerGroup.Children.Add(existingItemStub); var originalOwnerGroupContext = new PipingCalculationGroupContext(originalOwnerGroup, Enumerable.Empty(), Enumerable.Empty()); - var newOwnerGroup = new PipingCalculationGroup(); - var newOwnerGroupContext = new PipingCalculationGroupContext(newOwnerGroup, - Enumerable.Empty(), - Enumerable.Empty()); - - var sameNamedItem = mockRepository.Stub(); - sameNamedItem.Stub(i => i.Name).Return(calculation.Name); - + bool updatewasCalled = false; var originalOwnerObserver = mockRepository.StrictMock(); - originalOwnerObserver.Expect(o => o.UpdateObserver()); + originalOwnerObserver.Expect(o => o.UpdateObserver()).WhenCalled(invocation => updatewasCalled = true).Repeat.Once(); - var updateWasCalled = false; - var newOwnerObserver = mockRepository.StrictMock(); - newOwnerObserver.Expect(o => o.UpdateObserver()).WhenCalled(invocation => updateWasCalled = true); - var newOwnerGroupContextNode = mockRepository.Stub(); - newOwnerGroupContextNode.Expect(n => n.IsExpanded).Return(false); - newOwnerGroupContextNode.Expect(n => n.Expand()); // Must expand new owner, otherwise selecting dragged node could not be visible when parent is collapsed. + newOwnerGroupContextNode.Expect(n => n.IsExpanded).Return(true); - var preUpdateCalculationContextNode = mockRepository.Stub(); - preUpdateCalculationContextNode.Tag = calculationContext; - preUpdateCalculationContextNode.Expect(n => n.IsExpanded).Return(true); - preUpdateCalculationContextNode.Stub(n => n.Nodes).Return(new List()); + var preUpdateDraggedItemContextNode = mockRepository.Stub(); + preUpdateDraggedItemContextNode.Tag = draggedItemContext; + preUpdateDraggedItemContextNode.Expect(n => n.IsExpanded).Return(false); + preUpdateDraggedItemContextNode.Stub(n => n.Nodes).Return(new List()); - var postUpdateCalculationContextNode = mockRepository.Stub(); - postUpdateCalculationContextNode.Tag = calculationContext; - postUpdateCalculationContextNode.Expect(n => n.Parent).Return(newOwnerGroupContextNode); - postUpdateCalculationContextNode.Expect(n => n.IsExpanded).Return(false); - postUpdateCalculationContextNode.Expect(n => n.Expand()); - postUpdateCalculationContextNode.Stub(n => n.Nodes).Return(new List()); + var postUpdateDraggedItemContextNode = mockRepository.Stub(); + postUpdateDraggedItemContextNode.Tag = draggedItemContext; + postUpdateDraggedItemContextNode.Expect(n => n.Parent).Return(newOwnerGroupContextNode); + postUpdateDraggedItemContextNode.Expect(n => n.IsExpanded).Return(false); + postUpdateDraggedItemContextNode.Stub(n => n.Nodes).Return(new List()); var treeView = mockRepository.Stub(); - treeView.Expect(v => v.GetNodeByTag(calculationContext)).WhenCalled(invocation => + treeView.Expect(v => v.GetNodeByTag(draggedItemContext)).WhenCalled(invocation => { - if (updateWasCalled) + if (updatewasCalled) { - invocation.ReturnValue = postUpdateCalculationContextNode; + invocation.ReturnValue = postUpdateDraggedItemContextNode; } - }).Return(preUpdateCalculationContextNode).Repeat.Twice(); - treeView.Expect(v => v.StartLabelEdit()); + }).Return(preUpdateDraggedItemContextNode).Repeat.Twice(); var contextMenuBuilderProviderMock = mockRepository.StrictMock(); mockRepository.ReplayAll(); - newOwnerGroup.Children.Add(sameNamedItem); - originalOwnerGroup.Attach(originalOwnerObserver); - newOwnerGroup.Attach(newOwnerObserver); // Precondition: - CollectionAssert.Contains(originalOwnerGroup.Children, calculation); - CollectionAssert.DoesNotContain(newOwnerGroup.Children, calculation); - CollectionAssert.Contains(newOwnerGroup.Children.Select(c => c.Name), calculation.Name, - "Name of the dragged item should already exist in new owner."); + CollectionAssert.Contains(originalOwnerGroup.Children, draggedItem); var nodePresenter = new PipingCalculationGroupContextNodePresenter(contextMenuBuilderProviderMock) { TreeView = treeView }; // Call - nodePresenter.OnDragDrop(calculationContext, originalOwnerGroupContext, newOwnerGroupContext, DragOperations.Move, int.MaxValue); + nodePresenter.OnDragDrop(draggedItemContext, originalOwnerGroupContext, originalOwnerGroupContext, DragOperations.Move, newIndex); // Assert - CollectionAssert.DoesNotContain(originalOwnerGroup.Children, calculation); - CollectionAssert.Contains(newOwnerGroup.Children, calculation); - Assert.AreSame(calculation, newOwnerGroup.Children.Last()); - Assert.AreEqual("Nieuwe berekening (1)", calculation.Name); + CollectionAssert.Contains(originalOwnerGroup.Children, draggedItem); + Assert.AreSame(draggedItem, originalOwnerGroup.Children[newIndex], + "Dragging node to specific location within owning PipingCalculationGroup should put the dragged data at that index."); + Assert.AreEqual(name, draggedItem.Name, + "No renaming should occur when dragging within the same PipingCalculationGroup."); - Assert.AreSame(postUpdateCalculationContextNode, treeView.SelectedNode); + Assert.AreSame(postUpdateDraggedItemContextNode, treeView.SelectedNode); mockRepository.VerifyAll(); } [Test] - public void OnDragDrop_DraggingPipingCalculationGroupContextOntoGroup_MoveGroupInstanceToNewGroup() + [Combinatorial] + public void OnDragDrop_DraggingPipingCalculationContextOntoGroupStartWithSameNamedItem_MoveCalculationInstanceToNewGroupAndRename( + [Values(PipingCalculationItemType.Calculation, PipingCalculationItemType.Group)] PipingCalculationItemType draggedItemType) { // Setup - var group = new PipingCalculationGroup(); - var groupContext = new PipingCalculationGroupContext(group, - Enumerable.Empty(), - Enumerable.Empty()); + IPipingCalculationItem draggedItem = null; + object draggedItemContext = null; + + switch (draggedItemType) + { + case PipingCalculationItemType.Calculation: + var calculation = new PipingCalculation(); + draggedItem = calculation; + draggedItemContext = new PipingCalculationContext(calculation, + Enumerable.Empty(), + Enumerable.Empty()); + break; + case PipingCalculationItemType.Group: + var group = new PipingCalculationGroup(); + draggedItem = group; + draggedItemContext = new PipingCalculationGroupContext(group, + Enumerable.Empty(), + Enumerable.Empty()); + break; + default: + Assert.Fail(); + break; + } + var originalOwnerGroup = new PipingCalculationGroup(); - originalOwnerGroup.Children.Add(group); + originalOwnerGroup.Children.Add(draggedItem); var originalOwnerGroupContext = new PipingCalculationGroupContext(originalOwnerGroup, Enumerable.Empty(), Enumerable.Empty()); @@ -679,6 +615,9 @@ Enumerable.Empty(), Enumerable.Empty()); + var sameNamedItem = mockRepository.Stub(); + sameNamedItem.Stub(i => i.Name).Return(draggedItem.Name); + var originalOwnerObserver = mockRepository.StrictMock(); originalOwnerObserver.Expect(o => o.UpdateObserver()); @@ -690,144 +629,71 @@ newOwnerGroupContextNode.Expect(n => n.IsExpanded).Return(false); newOwnerGroupContextNode.Expect(n => n.Expand()); // Must expand new owner, otherwise selecting dragged node could not be visible when parent is collapsed. - var preUpdateGroupContextNode = mockRepository.Stub(); - preUpdateGroupContextNode.Tag = groupContext; - preUpdateGroupContextNode.Expect(n => n.IsExpanded).Return(false); - preUpdateGroupContextNode.Stub(n => n.Nodes).Return(new List()); + var preUpdateCalculationContextNode = mockRepository.Stub(); + preUpdateCalculationContextNode.Tag = draggedItemContext; + preUpdateCalculationContextNode.Expect(n => n.IsExpanded).Return(true); + preUpdateCalculationContextNode.Stub(n => n.Nodes).Return(new List()); var postUpdateCalculationContextNode = mockRepository.Stub(); - postUpdateCalculationContextNode.Tag = groupContext; + postUpdateCalculationContextNode.Tag = draggedItemContext; postUpdateCalculationContextNode.Expect(n => n.Parent).Return(newOwnerGroupContextNode); - postUpdateCalculationContextNode.Expect(n => n.IsExpanded).Return(true); - postUpdateCalculationContextNode.Expect(n => n.Collapse()); + postUpdateCalculationContextNode.Expect(n => n.IsExpanded).Return(false); + postUpdateCalculationContextNode.Expect(n => n.Expand()); postUpdateCalculationContextNode.Stub(n => n.Nodes).Return(new List()); var treeView = mockRepository.Stub(); - treeView.Expect(v => v.GetNodeByTag(groupContext)).WhenCalled(invocation => + treeView.Expect(v => v.GetNodeByTag(draggedItemContext)).WhenCalled(invocation => { if (updateWasCalled) { invocation.ReturnValue = postUpdateCalculationContextNode; } - }).Return(preUpdateGroupContextNode).Repeat.Twice(); - - var contextMenuBuilderProviderMock = mockRepository.StrictMock(); - - mockRepository.ReplayAll(); - - originalOwnerGroup.Attach(originalOwnerObserver); - newOwnerGroup.Attach(newOwnerObserver); - - // Precondition: - CollectionAssert.Contains(originalOwnerGroup.Children, group); - CollectionAssert.DoesNotContain(newOwnerGroup.Children, group); - - var nodePresenter = new PipingCalculationGroupContextNodePresenter(contextMenuBuilderProviderMock) - { - TreeView = treeView - }; - - // Call - nodePresenter.OnDragDrop(groupContext, originalOwnerGroupContext, newOwnerGroupContext, DragOperations.Move, int.MaxValue); - - // Assert - CollectionAssert.DoesNotContain(originalOwnerGroup.Children, group); - CollectionAssert.Contains(newOwnerGroup.Children, group); - Assert.AreSame(group, newOwnerGroup.Children.Last()); - - Assert.AreSame(postUpdateCalculationContextNode, treeView.SelectedNode); - - mockRepository.VerifyAll(); - } - - [Test] - public void OnDragDrop_DraggingPipingCalculationGroupContextOntoGroupWithSameNamedItem_MoveGroupInstanceToNewGroupAndRename() - { - // Setup - var group = new PipingCalculationGroup(); - var groupContext = new PipingCalculationGroupContext(group, - Enumerable.Empty(), - Enumerable.Empty()); - var originalOwnerGroup = new PipingCalculationGroup(); - originalOwnerGroup.Children.Add(group); - var originalOwnerGroupContext = new PipingCalculationGroupContext(originalOwnerGroup, - Enumerable.Empty(), - Enumerable.Empty()); - - var childWithSameName = mockRepository.Stub(); - childWithSameName.Stub(c => c.Name).Return(group.Name); - var newOwnerGroup = new PipingCalculationGroup(); - var newOwnerGroupContext = new PipingCalculationGroupContext(newOwnerGroup, - Enumerable.Empty(), - Enumerable.Empty()); - - var originalOwnerObserver = mockRepository.StrictMock(); - originalOwnerObserver.Expect(o => o.UpdateObserver()); - - var updateWasCalled = false; - var newOwnerObserver = mockRepository.StrictMock(); - newOwnerObserver.Expect(o => o.UpdateObserver()).WhenCalled(invocation => updateWasCalled = true); - - var newOwnerGroupContextNode = mockRepository.Stub(); - newOwnerGroupContextNode.Expect(n => n.IsExpanded).Return(false); - newOwnerGroupContextNode.Expect(n => n.Expand()); // Must expand new owner, otherwise selecting dragged node could not be visible when parent is collapsed. - - var preUpdateGroupContextNode = mockRepository.Stub(); - preUpdateGroupContextNode.Tag = groupContext; - preUpdateGroupContextNode.Expect(n => n.IsExpanded).Return(true); - preUpdateGroupContextNode.Stub(n => n.Nodes).Return(new List()); - - var postUpdateGroupContextNode = mockRepository.Stub(); - postUpdateGroupContextNode.Tag = groupContext; - postUpdateGroupContextNode.Expect(n => n.Parent).Return(newOwnerGroupContextNode); - postUpdateGroupContextNode.Expect(n => n.IsExpanded).Return(false); - postUpdateGroupContextNode.Expect(n => n.Expand()); - postUpdateGroupContextNode.Stub(n => n.Nodes).Return(new List()); - - var treeView = mockRepository.Stub(); - treeView.Expect(v => v.GetNodeByTag(groupContext)).WhenCalled(invocation => - { - if (updateWasCalled) - { - invocation.ReturnValue = postUpdateGroupContextNode; - } - }).Return(preUpdateGroupContextNode).Repeat.Twice(); + }).Return(preUpdateCalculationContextNode).Repeat.Twice(); treeView.Expect(v => v.StartLabelEdit()); var contextMenuBuilderProviderMock = mockRepository.StrictMock(); mockRepository.ReplayAll(); - newOwnerGroup.Children.Add(childWithSameName); + newOwnerGroup.Children.Add(sameNamedItem); originalOwnerGroup.Attach(originalOwnerObserver); newOwnerGroup.Attach(newOwnerObserver); // Precondition: - CollectionAssert.Contains(originalOwnerGroup.Children, group); - CollectionAssert.DoesNotContain(newOwnerGroup.Children, group); - CollectionAssert.Contains(newOwnerGroup.Children.Select(c=>c.Name), group.Name, - "Name of the dragged item should already exist within the new owner."); + 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."); var nodePresenter = new PipingCalculationGroupContextNodePresenter(contextMenuBuilderProviderMock) { TreeView = treeView }; // Call - nodePresenter.OnDragDrop(groupContext, originalOwnerGroupContext, newOwnerGroupContext, DragOperations.Move, int.MaxValue); + nodePresenter.OnDragDrop(draggedItemContext, originalOwnerGroupContext, newOwnerGroupContext, DragOperations.Move, 0); // Assert - CollectionAssert.DoesNotContain(originalOwnerGroup.Children, group); - CollectionAssert.Contains(newOwnerGroup.Children, group); - Assert.AreSame(group, newOwnerGroup.Children.Last()); - Assert.AreEqual("Nieuwe map (1)", group.Name); + 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 PipingCalculationItemType.Calculation: + Assert.AreEqual("Nieuwe berekening (1)", draggedItem.Name); + break; + case PipingCalculationItemType.Group: + Assert.AreEqual("Nieuwe map (1)", draggedItem.Name); + break; + } + + Assert.AreSame(postUpdateCalculationContextNode, treeView.SelectedNode); - Assert.AreSame(postUpdateGroupContextNode, treeView.SelectedNode); - mockRepository.VerifyAll(); } - + [Test] public void CanRenameNode_ParentIsPipingFailureMechanismNode_ReturnFalse() { @@ -1471,5 +1337,35 @@ Assert.AreSame(childGroup, returnedCalculationGroupContext.WrappedData); mockRepository.VerifyAll(); } + + /// + /// 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 PipingCalculationItemType + { + /// + /// Indicates . + /// + Calculation, + /// + /// Indicates . + /// + Group + } } } \ No newline at end of file