Index: Ringtoets/GrassCoverErosionInwards/src/Ringtoets.GrassCoverErosionInwards.Plugin/GrassCoverErosionInwardsGuiPlugin.cs =================================================================== diff -u -rc5f90c4f9b42d985f16f99ad8732576b9217267a -rb98bf88b9a483d6fe9669cf2dd207f4c65e7b5f1 --- Ringtoets/GrassCoverErosionInwards/src/Ringtoets.GrassCoverErosionInwards.Plugin/GrassCoverErosionInwardsGuiPlugin.cs (.../GrassCoverErosionInwardsGuiPlugin.cs) (revision c5f90c4f9b42d985f16f99ad8732576b9217267a) +++ Ringtoets/GrassCoverErosionInwards/src/Ringtoets.GrassCoverErosionInwards.Plugin/GrassCoverErosionInwardsGuiPlugin.cs (.../GrassCoverErosionInwardsGuiPlugin.cs) (revision b98bf88b9a483d6fe9669cf2dd207f4c65e7b5f1) @@ -75,8 +75,10 @@ EnsureVisibleOnCreate = grassCoverErosionInwardsCalculationGroupContext => true, ChildNodeObjects = CalculationGroupContextChildNodeObjects, ContextMenuStrip = CalculationGroupContextContextMenuStrip, - CanRename = CalculationGroupCanRename, - OnNodeRenamed = CalculationGroupOnNodeRenamed + CanRename = CalculationGroupContextCanRename, + OnNodeRenamed = CalculationGroupContextOnNodeRenamed, + CanRemove = CalculationGroupContextCanRemove, + OnNodeRemoved = CalculationGroupContextOnNodeRemoved }; yield return new TreeNodeInfo @@ -312,12 +314,36 @@ var builder = Gui.Get(nodeData, treeViewControl); - return builder - .AddOpenItem() - .AddSeparator() + if (parentData is GrassCoverErosionInwardsFailureMechanismContext) + { + builder + .AddOpenItem() + .AddSeparator(); + } + + builder .AddCustomItem(addCalculationGroupItem) .AddCustomItem(addCalculationItem) - .AddSeparator() + .AddSeparator(); + + var isRenamable = CalculationGroupContextCanRename(nodeData, parentData); + var isRemovable = CalculationGroupContextCanRemove(nodeData, parentData); + + if (isRenamable) + { + builder.AddRenameItem(); + } + if (isRemovable) + { + builder.AddDeleteItem(); + } + + if (isRemovable || isRenamable) + { + builder.AddSeparator(); + } + + return builder .AddImportItem() .AddExportItem() .AddSeparator() @@ -328,17 +354,33 @@ .Build(); } - private bool CalculationGroupCanRename(GrassCoverErosionInwardsCalculationGroupContext nodeData, object parentData) + private bool CalculationGroupContextCanRename(GrassCoverErosionInwardsCalculationGroupContext nodeData, object parentData) { return !(parentData is GrassCoverErosionInwardsFailureMechanismContext); } - private void CalculationGroupOnNodeRenamed(GrassCoverErosionInwardsCalculationGroupContext nodeData, string newName) + private void CalculationGroupContextOnNodeRenamed(GrassCoverErosionInwardsCalculationGroupContext nodeData, string newName) { nodeData.WrappedData.Name = newName; nodeData.NotifyObservers(); } + private bool CalculationGroupContextCanRemove(GrassCoverErosionInwardsCalculationGroupContext nodeData, object parentNodeData) + { + var group = parentNodeData as GrassCoverErosionInwardsCalculationGroupContext; + return group != null && group.WrappedData.Children.Contains(nodeData.WrappedData); + } + + private void CalculationGroupContextOnNodeRemoved(GrassCoverErosionInwardsCalculationGroupContext nodeData, object parentNodeData) + { + var group = parentNodeData as GrassCoverErosionInwardsCalculationGroupContext; + if (group != null) + { + group.WrappedData.Children.Remove(nodeData.WrappedData); + group.NotifyObservers(); + } + } + #endregion } } \ No newline at end of file Index: Ringtoets/GrassCoverErosionInwards/test/Ringtoets.GrassCoverErosionInwards.Forms.Test/TreeNodeInfos/GrassCoverErosionInwardsCalculationGroupContextTreeNodeInfoTest.cs =================================================================== diff -u -rfc6f7d48c14e74fddc94f0535a5bf2f6c04baf67 -rb98bf88b9a483d6fe9669cf2dd207f4c65e7b5f1 --- Ringtoets/GrassCoverErosionInwards/test/Ringtoets.GrassCoverErosionInwards.Forms.Test/TreeNodeInfos/GrassCoverErosionInwardsCalculationGroupContextTreeNodeInfoTest.cs (.../GrassCoverErosionInwardsCalculationGroupContextTreeNodeInfoTest.cs) (revision fc6f7d48c14e74fddc94f0535a5bf2f6c04baf67) +++ Ringtoets/GrassCoverErosionInwards/test/Ringtoets.GrassCoverErosionInwards.Forms.Test/TreeNodeInfos/GrassCoverErosionInwardsCalculationGroupContextTreeNodeInfoTest.cs (.../GrassCoverErosionInwardsCalculationGroupContextTreeNodeInfoTest.cs) (revision b98bf88b9a483d6fe9669cf2dd207f4c65e7b5f1) @@ -129,12 +129,12 @@ { // Setup var group = new CalculationGroup(); - var pipingFailureMechanismMock = mocks.StrictMock(); + var failureMechanismMock = mocks.StrictMock(); var assessmentSectionMock = mocks.StrictMock(); mocks.ReplayAll(); var groupContext = new GrassCoverErosionInwardsCalculationGroupContext(group, - pipingFailureMechanismMock, + failureMechanismMock, assessmentSectionMock); // Call @@ -182,7 +182,7 @@ } [Test] - public void ContextmenuStrip_Always_ReturnContextWithItems() + public void ContextmenuStrip_FailureMechanismContextParent_ReturnContextMenuWithoutRenameRemove() { // Setup var gui = mocks.StrictMock(); @@ -191,7 +191,7 @@ var failureMechanismMock = mocks.StrictMock(); var assessmentSectionMock = mocks.StrictMock(); - var parentData = new object(); + var parentData = new GrassCoverErosionInwardsFailureMechanismContext(failureMechanismMock, assessmentSectionMock); var nodeData = new GrassCoverErosionInwardsCalculationGroupContext(group, failureMechanismMock, assessmentSectionMock); @@ -215,17 +215,18 @@ ContextMenuStrip menu = info.ContextMenuStrip(nodeData, parentData, treeViewControl); // Assert + var mainCalculationGroupContextItemOffset = 2; Assert.AreEqual(12, menu.Items.Count); TestHelper.AssertContextMenuStripContainsItem(menu, 0, CoreCommonGuiResources.Open, CoreCommonGuiResources.Open_ToolTip, CoreCommonGuiResources.OpenIcon, false); - TestHelper.AssertContextMenuStripContainsItem(menu, 2, + TestHelper.AssertContextMenuStripContainsItem(menu, contextMenuAddCalculationGroupIndex + mainCalculationGroupContextItemOffset, RingtoetsFormsResources.CalculationGroup_Add_CalculationGroup, "Voeg een nieuwe berekeningsmap toe aan dit faalmechanisme.", RingtoetsFormsResources.AddFolderIcon); - TestHelper.AssertContextMenuStripContainsItem(menu, 3, + TestHelper.AssertContextMenuStripContainsItem(menu, contextMenuAddCalculationItemIndex + mainCalculationGroupContextItemOffset, RingtoetsFormsResources.CalculationGroup_Add_Calculation, "Voeg een nieuwe grasbekleding erosie kruin en binnentalud berekening toe aan dit faalmechanisme.", GrassCoverErosionInwardsFormResources.CalculationIcon); @@ -268,6 +269,102 @@ } [Test] + public void ContextmenuStrip_ChildOfGroup_ReturnContextMenuWithAllItems() + { + // Setup + var gui = mocks.StrictMock(); + var parentGroup = new CalculationGroup(); + var group = new CalculationGroup(); + + parentGroup.Children.Add(group); + + var failureMechanismMock = mocks.StrictMock(); + var assessmentSectionMock = mocks.StrictMock(); + + var parentData = new GrassCoverErosionInwardsCalculationGroupContext(parentGroup, + failureMechanismMock, + assessmentSectionMock); + + var nodeData = new GrassCoverErosionInwardsCalculationGroupContext(group, + failureMechanismMock, + assessmentSectionMock); + + var applicationFeatureCommandHandler = mocks.Stub(); + var exportImportHandler = mocks.Stub(); + var viewCommandsHandler = mocks.StrictMock(); + var treeViewControl = mocks.StrictMock(); + + var menuBuilder = new ContextMenuBuilder(applicationFeatureCommandHandler, exportImportHandler, viewCommandsHandler, nodeData, treeViewControl); + gui.Expect(g => g.Get(nodeData, treeViewControl)).Return(menuBuilder); + + treeViewControl.Expect(tvc => tvc.CanRenameNodeForData(nodeData)).Return(true); + treeViewControl.Expect(tvc => tvc.CanRemoveNodeForData(nodeData)).Return(true); + treeViewControl.Expect(tvc => tvc.CanExpandOrCollapseForData(nodeData)).Repeat.Twice().Return(false); + + mocks.ReplayAll(); + + plugin.Gui = gui; + + // Call + ContextMenuStrip menu = info.ContextMenuStrip(nodeData, parentData, treeViewControl); + + // Assert + Assert.AreEqual(13, menu.Items.Count); + TestHelper.AssertContextMenuStripContainsItem(menu, contextMenuAddCalculationGroupIndex, + RingtoetsFormsResources.CalculationGroup_Add_CalculationGroup, + "Voeg een nieuwe berekeningsmap toe aan dit faalmechanisme.", + RingtoetsFormsResources.AddFolderIcon); + TestHelper.AssertContextMenuStripContainsItem(menu, contextMenuAddCalculationItemIndex, + RingtoetsFormsResources.CalculationGroup_Add_Calculation, + "Voeg een nieuwe grasbekleding erosie kruin en binnentalud berekening toe aan dit faalmechanisme.", + GrassCoverErosionInwardsFormResources.CalculationIcon); + TestHelper.AssertContextMenuStripContainsItem(menu, 3, + CoreCommonGuiResources.Rename, + CoreCommonGuiResources.Rename_ToolTip, + CoreCommonGuiResources.RenameIcon); + TestHelper.AssertContextMenuStripContainsItem(menu, 4, + CoreCommonGuiResources.Delete, + CoreCommonGuiResources.Delete_ToolTip, + CoreCommonGuiResources.DeleteIcon); + TestHelper.AssertContextMenuStripContainsItem(menu, 6, + CoreCommonGuiResources.Import, + CoreCommonGuiResources.Import_ToolTip, + CoreCommonGuiResources.ImportIcon, + false); + TestHelper.AssertContextMenuStripContainsItem(menu, 7, + CoreCommonGuiResources.Export, + CoreCommonGuiResources.Export_ToolTip, + CoreCommonGuiResources.ExportIcon, + false); + + TestHelper.AssertContextMenuStripContainsItem(menu, 9, + CoreCommonGuiResources.Expand_all, + CoreCommonGuiResources.Expand_all_ToolTip, + CoreCommonGuiResources.ExpandAllIcon, + false); + TestHelper.AssertContextMenuStripContainsItem(menu, 10, + CoreCommonGuiResources.Collapse_all, + CoreCommonGuiResources.Collapse_all_ToolTip, + CoreCommonGuiResources.CollapseAllIcon, + false); + + TestHelper.AssertContextMenuStripContainsItem(menu, 12, + CoreCommonGuiResources.Properties, + CoreCommonGuiResources.Properties_ToolTip, + CoreCommonGuiResources.PropertiesHS, + false); + CollectionAssert.AllItemsAreInstancesOfType(new[] + { + menu.Items[2], + menu.Items[5], + menu.Items[8], + menu.Items[11] + }, typeof(ToolStripSeparator)); + + mocks.VerifyAll(); + } + + [Test] public void ContextMenuStrip_ClickOnAddGroupItem_AddGroupToCalculationGroupAndNotifyObservers() { // Setup @@ -366,7 +463,7 @@ } [Test] - public void CanRenameNode_ParentIsPipingFailureMechanismContext_ReturnFalse() + public void CanRenameNode_ParentIsGrassCoverErosionInwardsFailureMechanismContext_ReturnFalse() { // Setup var failureMechanismMock = mocks.StrictMock(); @@ -419,7 +516,161 @@ mocks.VerifyAll(); } - private const int contextMenuAddCalculationGroupIndex = 1; - private const int contextMenuAddCalculationItemIndex = 2; + [Test] + public void CanRemove_ParentIsFailureMechanism_ReturnFalse() + { + // Setup + var group = new CalculationGroup(); + var failureMechanismMock = mocks.StrictMock(); + var assessmentSectionMock = mocks.StrictMock(); + mocks.ReplayAll(); + + var nodeData = new GrassCoverErosionInwardsCalculationGroupContext(group, + failureMechanismMock, + assessmentSectionMock); + + var parentNodeData = new GrassCoverErosionInwardsFailureMechanism(); + parentNodeData.CalculationsGroup.Children.Add(group); + + mocks.ReplayAll(); + + // Call + bool isRemovalAllowed = info.CanRemove(nodeData, parentNodeData); + + // Assert + Assert.IsFalse(isRemovalAllowed); + mocks.VerifyAll(); + } + + [Test] + public void CanRemove_ParentIsGrasCoverErosionInwardsCalculationGroupContainingGroup_ReturnTrue() + { + // Setup + var group = new CalculationGroup(); + var failureMechanismMock = mocks.StrictMock(); + var assessmentSectionMock = mocks.StrictMock(); + mocks.ReplayAll(); + + var nodeData = new GrassCoverErosionInwardsCalculationGroupContext(group, + failureMechanismMock, + assessmentSectionMock); + + var parentGroup = new CalculationGroup(); + parentGroup.Children.Add(group); + var parentNodeData = new GrassCoverErosionInwardsCalculationGroupContext(parentGroup, + failureMechanismMock, + assessmentSectionMock); + + mocks.ReplayAll(); + + // Call + bool isRemovalAllowed = info.CanRemove(nodeData, parentNodeData); + + // Assert + Assert.IsTrue(isRemovalAllowed); + mocks.VerifyAll(); + } + + [Test] + public void CanRemove_ParentIsGrasCoverErosionInwardsCalculationGroupNotContainingGroup_ReturnFalse() + { + // Setup + var group = new CalculationGroup(); + var failureMechanismMock = mocks.StrictMock(); + var assessmentSectionMock = mocks.StrictMock(); + mocks.ReplayAll(); + + var nodeData = new GrassCoverErosionInwardsCalculationGroupContext(group, + failureMechanismMock, + assessmentSectionMock); + + var parentGroup = new CalculationGroup(); + var parentNodeData = new GrassCoverErosionInwardsCalculationGroupContext(parentGroup, + failureMechanismMock, + assessmentSectionMock); + + // Precondition + CollectionAssert.DoesNotContain(parentGroup.Children, group); + + // Call + bool isRemovalAllowed = info.CanRemove(nodeData, parentNodeData); + + // Assert + Assert.IsFalse(isRemovalAllowed); + } + + [Test] + public void OnNodeRemoved_ParentIsPipingCalculationGroupContainingGroup_RemoveGroupAndNotifyObservers() + { + // Setup + var observer = mocks.StrictMock(); + observer.Expect(o => o.UpdateObserver()); + var group = new CalculationGroup(); + var failureMechanismMock = mocks.StrictMock(); + var assessmentSectionMock = mocks.StrictMock(); + mocks.ReplayAll(); + + var nodeData = new GrassCoverErosionInwardsCalculationGroupContext(group, + failureMechanismMock, + assessmentSectionMock); + + var parentGroup = new CalculationGroup(); + parentGroup.Children.Add(group); + var parentNodeData = new GrassCoverErosionInwardsCalculationGroupContext(parentGroup, + failureMechanismMock, + assessmentSectionMock); + parentNodeData.Attach(observer); + + // Precondition + Assert.IsTrue(info.CanRemove(nodeData, parentNodeData)); + + // Call + info.OnNodeRemoved(nodeData, parentNodeData); + + // Assert + CollectionAssert.DoesNotContain(parentGroup.Children, group); + mocks.VerifyAll(); + } + + [Test] + public void OnNodeRemoved_ParentIsPipingCalculationGroupContainingGroupContainingCalculations_RemoveGroupAndCalculationsAndNotifyObservers() + { + // Setup + var observer = mocks.StrictMock(); + observer.Expect(o => o.UpdateObserver()); + var group = new CalculationGroup(); + var failureMechanismMock = mocks.StrictMock(); + + var calculation = new GrassCoverErosionInwardsCalculation(); + + group.Children.Add(calculation); + + var assessmentSectionMock = mocks.StrictMock(); + mocks.ReplayAll(); + + var nodeData = new GrassCoverErosionInwardsCalculationGroupContext(group, + failureMechanismMock, + assessmentSectionMock); + + var parentGroup = new CalculationGroup(); + parentGroup.Children.Add(group); + var parentNodeData = new GrassCoverErosionInwardsCalculationGroupContext(parentGroup, + failureMechanismMock, + assessmentSectionMock); + parentNodeData.Attach(observer); + + // Precondition + Assert.IsTrue(info.CanRemove(nodeData, parentNodeData)); + + // Call + info.OnNodeRemoved(nodeData, parentNodeData); + + // Assert + CollectionAssert.DoesNotContain(parentGroup.Children, group); + mocks.VerifyAll(); + } + + private const int contextMenuAddCalculationGroupIndex = 0; + private const int contextMenuAddCalculationItemIndex = 1; } } \ No newline at end of file Index: Ringtoets/Piping/src/Ringtoets.Piping.Plugin/PipingGuiPlugin.cs =================================================================== diff -u -rc5f90c4f9b42d985f16f99ad8732576b9217267a -rb98bf88b9a483d6fe9669cf2dd207f4c65e7b5f1 --- Ringtoets/Piping/src/Ringtoets.Piping.Plugin/PipingGuiPlugin.cs (.../PipingGuiPlugin.cs) (revision c5f90c4f9b42d985f16f99ad8732576b9217267a) +++ Ringtoets/Piping/src/Ringtoets.Piping.Plugin/PipingGuiPlugin.cs (.../PipingGuiPlugin.cs) (revision b98bf88b9a483d6fe9669cf2dd207f4c65e7b5f1) @@ -542,7 +542,7 @@ var succesfullyRemovedData = calculationGroupContext.WrappedData.Children.Remove(pipingCalculationContext.WrappedData); if (succesfullyRemovedData) { - RemoveCalculation(pipingCalculationContext.WrappedData, pipingCalculationContext.PipingFailureMechanism); + RemoveCalculationFromSectionResult(pipingCalculationContext.WrappedData, pipingCalculationContext.PipingFailureMechanism); calculationGroupContext.NotifyObservers(); } } @@ -804,12 +804,7 @@ private bool PipingCalculationGroupContextCanRemove(PipingCalculationGroupContext nodeData, object parentNodeData) { var group = parentNodeData as PipingCalculationGroupContext; - if (group != null) - { - return group.WrappedData.Children.Contains(nodeData.WrappedData); - } - - return false; + return group != null && group.WrappedData.Children.Contains(nodeData.WrappedData); } private void PipingCalculationGroupContextOnNodeRemoved(PipingCalculationGroupContext nodeData, object parentNodeData) @@ -821,14 +816,14 @@ foreach (var calculation in nodeData.WrappedData.GetCalculations().Cast()) { - RemoveCalculation(calculation, nodeData.PipingFailureMechanism); + RemoveCalculationFromSectionResult(calculation, nodeData.PipingFailureMechanism); } group.NotifyObservers(); } } - private void RemoveCalculation(PipingCalculationScenario calculation, PipingFailureMechanism pipingFailureMechanism) + private void RemoveCalculationFromSectionResult(PipingCalculationScenario calculation, PipingFailureMechanism pipingFailureMechanism) { PipingCalculationScenarioService.RemoveCalculationScenarioFromSectionResult(calculation, pipingFailureMechanism); }