Index: Ringtoets/Piping/src/Ringtoets.Piping.Forms/NodePresenters/PipingCalculationGroupContextNodePresenter.cs =================================================================== diff -u -r329872d1f64548ecc892821c031ee334de88e099 -r48b6dd6e6c77ef3075bbeb78858d2300e85cdf68 --- Ringtoets/Piping/src/Ringtoets.Piping.Forms/NodePresenters/PipingCalculationGroupContextNodePresenter.cs (.../PipingCalculationGroupContextNodePresenter.cs) (revision 329872d1f64548ecc892821c031ee334de88e099) +++ Ringtoets/Piping/src/Ringtoets.Piping.Forms/NodePresenters/PipingCalculationGroupContextNodePresenter.cs (.../PipingCalculationGroupContextNodePresenter.cs) (revision 48b6dd6e6c77ef3075bbeb78858d2300e85cdf68) @@ -45,14 +45,34 @@ var targetGroup = ((PipingCalculationGroupContext)targetNode.Tag).WrappedData; IPipingCalculationItem pipingCalculationItem = GetAsIPipingCalculationItem(item); - if (pipingCalculationItem != null && !targetGroup.Children.Contains(pipingCalculationItem)) + if (pipingCalculationItem != null && !targetGroup.Children.Contains(pipingCalculationItem) && NodesHaveSameParentFailureMechanism(sourceNode, targetNode)) { return validOperations; } return base.CanDrop(item, sourceNode, targetNode, validOperations); } + private bool NodesHaveSameParentFailureMechanism(ITreeNode sourceNode, ITreeNode targetNode) + { + 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.Parent.Tag as PipingFailureMechanism) == null) + { + // No parent found, go search higher up hierarchy! + node = node.Parent; + } + return sourceFailureMechanism; + } + public override bool CanRenameNode(ITreeNode node) { return node.Parent == null || !(node.Parent.Tag is PipingFailureMechanism); Index: Ringtoets/Piping/test/Ringtoets.Piping.Forms.Test/NodePresenters/PipingCalculationGroupContextNodePresenterTest.cs =================================================================== diff -u -r329872d1f64548ecc892821c031ee334de88e099 -r48b6dd6e6c77ef3075bbeb78858d2300e85cdf68 --- Ringtoets/Piping/test/Ringtoets.Piping.Forms.Test/NodePresenters/PipingCalculationGroupContextNodePresenterTest.cs (.../PipingCalculationGroupContextNodePresenterTest.cs) (revision 329872d1f64548ecc892821c031ee334de88e099) +++ Ringtoets/Piping/test/Ringtoets.Piping.Forms.Test/NodePresenters/PipingCalculationGroupContextNodePresenterTest.cs (.../PipingCalculationGroupContextNodePresenterTest.cs) (revision 48b6dd6e6c77ef3075bbeb78858d2300e85cdf68) @@ -183,29 +183,45 @@ var calculationContext = new PipingCalculationContext(calculation, Enumerable.Empty(), Enumerable.Empty()); - 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(calculation); + failureMechanism.CalculationsGroup.Children.Add(targetGroup); + #region Mock node tree for source and target 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 calculationNode = mockRepository.Stub(); - calculationNode.Tag = calculation; + calculationNode.Tag = calculationContext; + calculationNode.Expect(n => n.Parent).Return(failureMechanismGroupNode).Repeat.AtLeastOnce(); - var groupNode = mockRepository.Stub(); - groupNode.Tag = groupContext; + var targetGroupNode = mockRepository.Stub(); + targetGroupNode.Tag = targetGroupContext; + targetGroupNode.Expect(n => n.Parent).Return(failureMechanismGroupNode).Repeat.AtLeastOnce(); + #endregion + var contextMenuBuilderProviderMock = mockRepository.StrictMock(); mockRepository.ReplayAll(); // Precondition: - CollectionAssert.DoesNotContain(group.Children, calculation, + 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); + DragOperations supportedOperations = nodePresenter.CanDrop(calculationContext, calculationNode, targetGroupNode, DragOperations.Move); // Assert Assert.AreEqual(DragOperations.Move, supportedOperations); @@ -220,24 +236,24 @@ var calculationContext = new PipingCalculationContext(calculation, Enumerable.Empty(), Enumerable.Empty()); - var group = new PipingCalculationGroup(); - group.Children.Add(calculation); - var groupContext = new PipingCalculationGroupContext(group, - Enumerable.Empty(), - Enumerable.Empty()); + var targetGroup = new PipingCalculationGroup(); + targetGroup.Children.Add(calculation); + var targetGroupContext = new PipingCalculationGroupContext(targetGroup, + Enumerable.Empty(), + Enumerable.Empty()); var calculationNode = mockRepository.Stub(); calculationNode.Tag = calculationContext; var groupNode = mockRepository.Stub(); - groupNode.Tag = groupContext; + groupNode.Tag = targetGroupContext; var contextMenuBuilderProviderMock = mockRepository.StrictMock(); mockRepository.ReplayAll(); // Precondition: - CollectionAssert.Contains(group.Children, calculation, + 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); @@ -251,6 +267,72 @@ } [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); + + 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 calculationNode = mockRepository.Stub(); + calculationNode.Tag = calculationContext; + calculationNode.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 groupNode = mockRepository.Stub(); + groupNode.Tag = targetGroupContext; + groupNode.Expect(n => n.Parent).Return(targetFailureMechanismGroupNode).Repeat.AtLeastOnce(); + + #endregion + + var contextMenuBuilderProviderMock = mockRepository.StrictMock(); + + 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); + + // Assert + Assert.AreEqual(DragOperations.None, supportedOperations); + mockRepository.ReplayAll(); + } + + [Test] public void CanDrop_DraggingPipingCalculationGroupContextOntoGroupNotContainingGroup_ReturnMove() { // Setup @@ -263,12 +345,30 @@ 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(); mockRepository.ReplayAll(); @@ -326,6 +426,72 @@ } [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