// 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.Collections; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Windows.Forms; using Core.Common.Controls.TreeView; using Core.Common.Gui.ContextMenu; using Core.Common.Gui.Forms; using Core.Common.Gui.Forms.ProgressDialog; using Core.Common.Gui.Plugin; using Ringtoets.Common.Data; using Ringtoets.Common.Forms.Helpers; using Ringtoets.Common.Forms.PresentationObjects; using Ringtoets.Piping.Data; using Ringtoets.Piping.Forms.PresentationObjects; using Ringtoets.Piping.Forms.PropertyClasses; using Ringtoets.Piping.Service; using PipingDataResources = Ringtoets.Piping.Data.Properties.Resources; using RingtoetsCommonFormsResources = Ringtoets.Common.Forms.Properties.Resources; using RingtoetsFormsResources = Ringtoets.Common.Forms.Properties.Resources; using PipingFormsResources = Ringtoets.Piping.Forms.Properties.Resources; using BaseResources = Core.Common.Base.Properties.Resources; namespace Ringtoets.Piping.Plugin { public class PipingGuiPlugin : GuiPlugin { public override IRibbonCommandHandler RibbonCommandHandler { get { return new PipingRibbon(); } } public override IEnumerable GetPropertyInfos() { yield return new PropertyInfo(); yield return new PropertyInfo(); yield return new PropertyInfo(); yield return new PropertyInfo(); yield return new PropertyInfo(); yield return new PropertyInfo(); } public override IEnumerable GetTreeNodeInfos() { yield return new TreeNodeInfo { Text = pipingFailureMechanism => pipingFailureMechanism.Name, Image = pipingFailureMechanism => PipingFormsResources.PipingIcon, ContextMenuStrip = FailureMechanismContextMenuStrip, ChildNodeObjects = FailureMechanismChildNodeObjects, }; yield return new TreeNodeInfo { Text = pipingCalculationContext => pipingCalculationContext.WrappedData.Name, Image = pipingCalculationContext => PipingFormsResources.PipingIcon, EnsureVisibleOnCreate = pipingCalculationContext => true, ContextMenuStrip = PipingCalculationContextContextMenuStrip, ChildNodeObjects = PipingCalculationContextChildNodeObjects, CanRename = (pipingCalculationContext, parentData) => true, OnNodeRenamed = PipingCalculationContextOnNodeRenamed, CanRemove = PipingCalculationContextCanRemove, OnNodeRemoved = PipingCalculationContextOnNodeRemoved, CanDrag = (pipingCalculationContext, parentData) => true }; yield return new TreeNodeInfo { Text = pipingCalculationGroupContext => pipingCalculationGroupContext.WrappedData.Name, Image = pipingCalculationGroupContext => PipingFormsResources.FolderIcon, EnsureVisibleOnCreate = pipingCalculationGroupContext => true, ChildNodeObjects = PipingCalculationGroupContextChildNodeObjects, ContextMenuStrip = PipingCalculationGroupContextContextMenuStrip, CanRename = PipingCalculationGroupContextCanRenameNode, OnNodeRenamed = PipingCalculationGroupContextOnNodeRenamed, CanRemove = PipingCalculationGroupContextCanRemove, OnNodeRemoved = PipingCalculationGroupContextOnNodeRemoved, CanDrag = PipingCalculationGroupContextCanDrag, CanDrop = PipingCalculationGroupContextCanDropOrCanInsert, CanInsert = PipingCalculationGroupContextCanDropOrCanInsert, OnDrop = PipingCalculationGroupContextOnDrop }; yield return new TreeNodeInfo { Text = pipingInputContext => PipingFormsResources.PipingInputContext_NodeDisplayName, Image = pipingInputContext => PipingFormsResources.PipingInputIcon, ContextMenuStrip = (nodeData, parentData, treeViewControl) => Gui.Get(nodeData, treeViewControl) .AddImportItem() .AddExportItem() .AddSeparator() .AddPropertiesItem() .Build() }; yield return new TreeNodeInfo> { Text = ringtoetsPipingSurfaceLine => PipingFormsResources.PipingSurfaceLinesCollection_DisplayName, Image = ringtoetsPipingSurfaceLine => PipingFormsResources.FolderIcon, ForeColor = ringtoetsPipingSurfaceLine => ringtoetsPipingSurfaceLine.Any() ? Color.FromKnownColor(KnownColor.ControlText) : Color.FromKnownColor(KnownColor.GrayText), ChildNodeObjects = ringtoetsPipingSurfaceLine => ringtoetsPipingSurfaceLine.Cast().ToArray(), ContextMenuStrip = (nodeData, parentData, treeViewControl) => Gui.Get(nodeData, treeViewControl) .AddImportItem() .AddExportItem() .AddSeparator() .AddExpandAllItem() .AddCollapseAllItem() .Build() }; yield return new TreeNodeInfo { Text = pipingSurfaceLine => pipingSurfaceLine.Name, Image = pipingSurfaceLine => PipingFormsResources.PipingSurfaceLineIcon, ContextMenuStrip = (nodeData, parentData, treeViewControl) => Gui.Get(nodeData, treeViewControl) .AddPropertiesItem() .Build() }; yield return new TreeNodeInfo> { Text = pipingSoilProfiles => PipingFormsResources.PipingSoilProfilesCollection_DisplayName, Image = pipingSoilProfiles => PipingFormsResources.FolderIcon, ForeColor = pipingSoilProfiles => pipingSoilProfiles.Any() ? Color.FromKnownColor(KnownColor.ControlText) : Color.FromKnownColor(KnownColor.GrayText), ChildNodeObjects = pipingSoilProfiles => pipingSoilProfiles.Cast().ToArray(), ContextMenuStrip = (nodeData, parentData, treeViewControl) => Gui.Get(nodeData, treeViewControl) .AddImportItem() .AddExportItem() .AddSeparator() .AddExpandAllItem() .AddCollapseAllItem() .Build() }; yield return new TreeNodeInfo { Text = pipingSoilProfile => pipingSoilProfile.Name, Image = pipingSoilProfile => PipingFormsResources.PipingSoilProfileIcon, ContextMenuStrip = (nodeData, parentData, treeViewControl) => Gui.Get(nodeData, treeViewControl) .AddPropertiesItem() .Build() }; yield return new TreeNodeInfo { Text = pipingOutput => PipingFormsResources.PipingOutput_DisplayName, Image = pipingOutput => PipingFormsResources.PipingOutputIcon, ContextMenuStrip = (nodeData, parentData, treeViewControl) => Gui.Get(nodeData, treeViewControl) .AddExportItem() .AddSeparator() .AddPropertiesItem() .Build() }; yield return new TreeNodeInfo { Text = emptyPipingOutput => PipingFormsResources.PipingOutput_DisplayName, Image = emptyPipingOutput => PipingFormsResources.PipingOutputIcon, ForeColor = emptyPipingOutput => Color.FromKnownColor(KnownColor.GrayText), ContextMenuStrip = (nodeData, parentData, treeViewControl) => Gui.Get(nodeData, treeViewControl) .AddExportItem() .AddSeparator() .AddPropertiesItem() .Build() }; yield return new TreeNodeInfo { Text = emptyPipingCalculationReport => PipingDataResources.CalculationReport_DisplayName, Image = emptyPipingCalculationReport => PipingFormsResources.PipingCalculationReportIcon, ForeColor = emptyPipingCalculationReport => Color.FromKnownColor(KnownColor.GrayText), ContextMenuStrip = (nodeData, parentData, treeViewControl) => Gui.Get(nodeData, treeViewControl) .AddOpenItem() .AddSeparator() .AddExportItem() .AddSeparator() .AddPropertiesItem() .Build() }; } # region PipingFailureMechanism TreeNodeInfo private ContextMenuStrip FailureMechanismContextMenuStrip(PipingFailureMechanism failureMechanism, object parentData, TreeViewControl treeViewControl) { var addCalculationGroupItem = new StrictContextMenuItem( PipingFormsResources.PipingCalculationGroup_Add_PipingCalculationGroup, PipingFormsResources.PipingFailureMechanism_Add_PipingCalculationGroup_Tooltip, PipingFormsResources.AddFolderIcon, (o, args) => AddCalculationGroup(failureMechanism) ); var addCalculationItem = new StrictContextMenuItem( PipingFormsResources.PipingCalculationGroup_Add_PipingCalculation, PipingFormsResources.PipingFailureMechanism_Add_PipingCalculation_Tooltip, PipingFormsResources.PipingIcon, (s, e) => AddCalculation(failureMechanism) ); var validateAllItem = CreateValidateAllItem(failureMechanism); var calculateAllItem = CreateCalculateAllItem(failureMechanism); var clearAllItem = new StrictContextMenuItem( RingtoetsCommonFormsResources.Clear_all_output, RingtoetsCommonFormsResources.Clear_all_output_ToolTip, RingtoetsCommonFormsResources.ClearIcon, (o, args) => ClearAll(failureMechanism) ); if (!GetAllPipingCalculations(failureMechanism).Any(c => c.HasOutput)) { clearAllItem.Enabled = false; clearAllItem.ToolTipText = PipingFormsResources.PipingCalculationGroup_ClearOutput_No_calculation_with_output_to_clear; } return Gui.Get(failureMechanism, treeViewControl) .AddOpenItem() .AddSeparator() .AddCustomItem(addCalculationGroupItem) .AddCustomItem(addCalculationItem) .AddSeparator() .AddCustomItem(validateAllItem) .AddCustomItem(calculateAllItem) .AddCustomItem(clearAllItem) .AddSeparator() .AddImportItem() .AddExportItem() .AddSeparator() .AddExpandAllItem() .AddCollapseAllItem() .Build(); } private static IEnumerable GetAllPipingCalculations(PipingFailureMechanism failureMechanism) { return failureMechanism.CalculationItems.OfType(); } private StrictContextMenuItem CreateCalculateAllItem(PipingFailureMechanism failureMechanism) { var menuItem = new StrictContextMenuItem( RingtoetsCommonFormsResources.Calculate_all, RingtoetsCommonFormsResources.Calculate_all_ToolTip, RingtoetsCommonFormsResources.CalculateAllIcon, (o, args) => CalculateAll(failureMechanism) ); if (!GetAllPipingCalculations(failureMechanism).Any()) { menuItem.Enabled = false; menuItem.ToolTipText = PipingFormsResources.PipingFailureMechanism_CreateCalculateAllItem_No_calculations_to_run; } return menuItem; } private StrictContextMenuItem CreateValidateAllItem(PipingFailureMechanism failureMechanism) { var menuItem = new StrictContextMenuItem( RingtoetsCommonFormsResources.Validate_all, RingtoetsCommonFormsResources.Validate_all_ToolTip, RingtoetsCommonFormsResources.ValidateAllIcon, (o, args) => ValidateAll(failureMechanism) ); if (!GetAllPipingCalculations(failureMechanism).Any()) { menuItem.Enabled = false; menuItem.ToolTipText = PipingFormsResources.PipingFailureMechanism_CreateValidateAllItem_No_calculations_to_validate; } return menuItem; } private static void ClearAll(PipingFailureMechanism failureMechanism) { if (MessageBox.Show(PipingFormsResources.PipingCalculationGroupContext_ContextMenuStrip_Are_you_sure_clear_all_output, BaseResources.Confirm, MessageBoxButtons.OKCancel) != DialogResult.OK) { return; } foreach (ICalculationItem calc in failureMechanism.CalculationItems) { calc.ClearOutput(); calc.NotifyObservers(); } } private void ValidateAll(PipingFailureMechanism failureMechanism) { foreach (PipingCalculation calculation in GetAllPipingCalculations(failureMechanism)) { PipingCalculationService.Validate(calculation); } } private void CalculateAll(PipingFailureMechanism failureMechanism) { ActivityProgressDialogRunner.Run(Gui.MainWindow, GetAllPipingCalculations(failureMechanism).Select(calc => new PipingCalculationActivity(calc))); } private void AddCalculationGroup(PipingFailureMechanism failureMechanism) { var calculation = new PipingCalculationGroup { Name = NamingHelper.GetUniqueName(failureMechanism.CalculationsGroup.Children, PipingDataResources.PipingCalculationGroup_DefaultName, c => c.Name) }; failureMechanism.CalculationsGroup.Children.Add(calculation); failureMechanism.CalculationsGroup.NotifyObservers(); } private void AddCalculation(PipingFailureMechanism failureMechanism) { var calculation = new PipingCalculation { Name = NamingHelper.GetUniqueName(failureMechanism.CalculationsGroup.Children, PipingDataResources.PipingCalculation_DefaultName, c => c.Name) }; failureMechanism.CalculationsGroup.Children.Add(calculation); failureMechanism.CalculationsGroup.NotifyObservers(); } private object[] FailureMechanismChildNodeObjects(PipingFailureMechanism pipingFailureMechanism) { return new object[] { new CategoryTreeFolder(RingtoetsCommonFormsResources.FailureMechanism_Inputs_DisplayName, GetInputs(pipingFailureMechanism), TreeFolderCategory.Input), new PipingCalculationGroupContext(pipingFailureMechanism.CalculationsGroup, pipingFailureMechanism.SurfaceLines, pipingFailureMechanism.SoilProfiles, pipingFailureMechanism), new CategoryTreeFolder(RingtoetsCommonFormsResources.FailureMechanism_Outputs_DisplayName, GetOutputs(pipingFailureMechanism), TreeFolderCategory.Output) }; } private static IList GetInputs(PipingFailureMechanism failureMechanism) { return new ArrayList { failureMechanism.SectionDivisions, failureMechanism.SurfaceLines, failureMechanism.SoilProfiles, failureMechanism.BoundaryConditions }; } private IList GetOutputs(PipingFailureMechanism failureMechanism) { return new ArrayList { failureMechanism.AssessmentResult }; } # endregion # region PipingCalculationContext TreeNodeInfo private ContextMenuStrip PipingCalculationContextContextMenuStrip(PipingCalculationContext nodeData, object parentData, TreeViewControl treeViewControl) { PipingCalculation calculation = nodeData.WrappedData; var validateItem = new StrictContextMenuItem(RingtoetsFormsResources.Validate, RingtoetsFormsResources.Validate_ToolTip, RingtoetsFormsResources.ValidateIcon, (o, args) => { PipingCalculationService.Validate(calculation); }); var calculateItem = new StrictContextMenuItem(RingtoetsFormsResources.Calculate, RingtoetsFormsResources.Calculate_ToolTip, RingtoetsFormsResources.CalculateIcon, (o, args) => { ActivityProgressDialogRunner.Run(Gui.MainWindow, new PipingCalculationActivity(calculation)); }); var clearOutputItem = new StrictContextMenuItem(PipingFormsResources.Clear_output, PipingFormsResources.Clear_output_ToolTip, RingtoetsFormsResources.ClearIcon, (o, args) => ClearOutput(calculation)); if (!calculation.HasOutput) { clearOutputItem.Enabled = false; clearOutputItem.ToolTipText = PipingFormsResources.ClearOutput_No_output_to_clear; } return Gui.Get(nodeData, treeViewControl) .AddCustomItem(validateItem) .AddCustomItem(calculateItem) .AddCustomItem(clearOutputItem) .AddSeparator() .AddRenameItem() .AddDeleteItem() .AddSeparator() .AddImportItem() .AddExportItem() .AddSeparator() .AddExpandAllItem() .AddCollapseAllItem() .AddSeparator() .AddPropertiesItem() .Build(); } private static object[] PipingCalculationContextChildNodeObjects(PipingCalculationContext pipingCalculationContext) { var childNodes = new List { pipingCalculationContext.WrappedData.Comments, new PipingInputContext(pipingCalculationContext.WrappedData.InputParameters, pipingCalculationContext.AvailablePipingSurfaceLines, pipingCalculationContext.AvailablePipingSoilProfiles) }; if (pipingCalculationContext.WrappedData.HasOutput) { childNodes.Add(pipingCalculationContext.WrappedData.Output); childNodes.Add(new EmptyPipingCalculationReport()); } else { childNodes.Add(new EmptyPipingOutput()); childNodes.Add(new EmptyPipingCalculationReport()); } return childNodes.ToArray(); } private static void PipingCalculationContextOnNodeRenamed(PipingCalculationContext pipingCalculationContext, string newName) { pipingCalculationContext.WrappedData.Name = newName; pipingCalculationContext.WrappedData.NotifyObservers(); } private bool PipingCalculationContextCanRemove(PipingCalculationContext pipingCalculationContext, object parentNodeData) { var calculationGroupContext = parentNodeData as PipingCalculationGroupContext; if (calculationGroupContext != null) { return calculationGroupContext.WrappedData.Children.Contains(pipingCalculationContext.WrappedData); } return false; } private static void PipingCalculationContextOnNodeRemoved(PipingCalculationContext pipingCalculationContext, object parentNodeData) { var calculationGroupContext = parentNodeData as PipingCalculationGroupContext; if (calculationGroupContext != null) { var succesfullyRemovedData = calculationGroupContext.WrappedData.Children.Remove(pipingCalculationContext.WrappedData); if (succesfullyRemovedData) { calculationGroupContext.NotifyObservers(); } } } private static void ClearOutput(PipingCalculation calculation) { if (MessageBox.Show(PipingFormsResources.PipingCalculationContext_ContextMenuStrip_Are_you_sure_clear_output, BaseResources.Confirm, MessageBoxButtons.OKCancel) != DialogResult.OK) { return; } calculation.ClearOutput(); calculation.NotifyObservers(); } # endregion # region PipingCalculationGroupContext TreeNodeInfo private object[] PipingCalculationGroupContextChildNodeObjects(PipingCalculationGroupContext nodeData) { var childNodeObjects = new List(); foreach (IPipingCalculationItem item in nodeData.WrappedData.Children) { var calculation = item as PipingCalculation; var group = item as PipingCalculationGroup; if (calculation != null) { childNodeObjects.Add(new PipingCalculationContext(calculation, nodeData.AvailablePipingSurfaceLines, nodeData.AvailablePipingSoilProfiles, nodeData.PipingFailureMechanism)); } else if (group != null) { childNodeObjects.Add(new PipingCalculationGroupContext(group, nodeData.AvailablePipingSurfaceLines, nodeData.AvailablePipingSoilProfiles, nodeData.PipingFailureMechanism)); } else { childNodeObjects.Add(item); } } return childNodeObjects.ToArray(); } private ContextMenuStrip PipingCalculationGroupContextContextMenuStrip(PipingCalculationGroupContext nodeData, object parentData, TreeViewControl treeViewControl) { var group = nodeData.WrappedData; var addCalculationGroupItem = new StrictContextMenuItem( PipingFormsResources.PipingCalculationGroup_Add_PipingCalculationGroup, PipingFormsResources.PipingCalculationGroup_Add_PipingCalculationGroup_ToolTip, PipingFormsResources.AddFolderIcon, (o, args) => { var newGroup = new PipingCalculationGroup { Name = NamingHelper.GetUniqueName(group.Children, PipingDataResources.PipingCalculationGroup_DefaultName, c => c.Name) }; group.Children.Add(newGroup); nodeData.NotifyObservers(); }); var addCalculationItem = new StrictContextMenuItem( PipingFormsResources.PipingCalculationGroup_Add_PipingCalculation, PipingFormsResources.PipingCalculationGroup_Add_PipingCalculation_ToolTip, PipingFormsResources.PipingIcon, (o, args) => { var calculation = new PipingCalculation { Name = NamingHelper.GetUniqueName(group.Children, PipingDataResources.PipingCalculation_DefaultName, c => c.Name) }; group.Children.Add(calculation); nodeData.NotifyObservers(); }); var validateAllItem = CreateValidateAllItem(group); var calculateAllItem = CreateCalculateAllItem(group); var clearAllItem = new StrictContextMenuItem( RingtoetsFormsResources.Clear_all_output, PipingFormsResources.PipingCalculationGroup_ClearOutput_ToolTip, RingtoetsFormsResources.ClearIcon, (o, args) => { if (MessageBox.Show(PipingFormsResources.PipingCalculationGroupContext_ContextMenuStrip_Are_you_sure_clear_all_output, BaseResources.Confirm, MessageBoxButtons.OKCancel) != DialogResult.OK) { return; } foreach (PipingCalculation calc in group.GetPipingCalculations().Where(c => c.HasOutput)) { calc.ClearOutput(); calc.NotifyObservers(); } }); if (!nodeData.WrappedData.GetPipingCalculations().Any(c => c.HasOutput)) { clearAllItem.Enabled = false; clearAllItem.ToolTipText = PipingFormsResources.PipingCalculationGroup_ClearOutput_No_calculation_with_output_to_clear; } var builder = Gui.Get(nodeData, treeViewControl) .AddCustomItem(addCalculationGroupItem) .AddCustomItem(addCalculationItem) .AddSeparator() .AddCustomItem(validateAllItem) .AddCustomItem(calculateAllItem) .AddCustomItem(clearAllItem) .AddSeparator(); var isRenamable = PipingCalculationGroupContextCanRenameNode(nodeData, parentData); var isRemovable = PipingCalculationGroupContextCanRemove(nodeData, parentData); if (isRenamable) { builder.AddRenameItem(); } if (isRemovable) { builder.AddDeleteItem(); } if (isRemovable || isRenamable) { builder.AddSeparator(); } return builder .AddImportItem() .AddExportItem() .AddSeparator() .AddExpandAllItem() .AddCollapseAllItem() .AddSeparator() .AddPropertiesItem() .Build(); } private StrictContextMenuItem CreateCalculateAllItem(PipingCalculationGroup group) { var menuItem = new StrictContextMenuItem( RingtoetsFormsResources.Calculate_all, PipingFormsResources.PipingCalculationGroup_CalculateAll_ToolTip, RingtoetsFormsResources.CalculateAllIcon, (o, args) => { CalculateAll(group); }); if (!group.GetPipingCalculations().Any()) { menuItem.Enabled = false; menuItem.ToolTipText = PipingFormsResources.PipingFailureMechanism_CreateCalculateAllItem_No_calculations_to_run; } return menuItem; } private static StrictContextMenuItem CreateValidateAllItem(PipingCalculationGroup group) { var menuItem = new StrictContextMenuItem( RingtoetsFormsResources.Validate_all, PipingFormsResources.PipingCalculationGroup_Validate_All_ToolTip, RingtoetsFormsResources.ValidateAllIcon, (o, args) => { ValidateAll(group); }); if (!group.GetPipingCalculations().Any()) { menuItem.Enabled = false; menuItem.ToolTipText = PipingFormsResources.PipingFailureMechanism_CreateValidateAllItem_No_calculations_to_validate; } return menuItem; } private void CalculateAll(PipingCalculationGroup group) { ActivityProgressDialogRunner.Run(Gui.MainWindow, group.GetPipingCalculations().Select(pc => new PipingCalculationActivity(pc))); } private static void ValidateAll(PipingCalculationGroup group) { foreach (PipingCalculation calculation in group.Children.GetPipingCalculations()) { PipingCalculationService.Validate(calculation); } } private bool PipingCalculationGroupContextCanRenameNode(PipingCalculationGroupContext pipingCalculationGroupContext, object parentData) { return !(parentData is PipingFailureMechanism); } private void PipingCalculationGroupContextOnNodeRenamed(PipingCalculationGroupContext nodeData, string newName) { nodeData.WrappedData.Name = newName; nodeData.NotifyObservers(); } private bool PipingCalculationGroupContextCanRemove(PipingCalculationGroupContext nodeData, object parentNodeData) { var group = parentNodeData as PipingCalculationGroupContext; if (group != null) { return group.WrappedData.Children.Contains(nodeData.WrappedData); } return false; } private void PipingCalculationGroupContextOnNodeRemoved(PipingCalculationGroupContext nodeData, object parentNodeData) { var group = parentNodeData as PipingCalculationGroupContext; if (group != null) { group.WrappedData.Children.Remove(nodeData.WrappedData); group.NotifyObservers(); } } private bool PipingCalculationGroupContextCanDrag(PipingCalculationGroupContext nodeData, object parentData) { if (parentData is PipingFailureMechanism) { return false; } return true; } private bool PipingCalculationGroupContextCanDropOrCanInsert(object draggedData, object targetData) { return GetAsIPipingCalculationItem(draggedData) != null && NodesHaveSameParentFailureMechanism(draggedData, targetData); } private static IPipingCalculationItem GetAsIPipingCalculationItem(object item) { var calculationContext = item as PipingCalculationContext; if (calculationContext != null) { return calculationContext.WrappedData; } var groupContext = item as PipingCalculationGroupContext; if (groupContext != null) { return groupContext.WrappedData; } return null; } private bool NodesHaveSameParentFailureMechanism(object draggedData, object targetData) { var sourceFailureMechanism = GetParentFailureMechanism(draggedData); var targetFailureMechanism = GetParentFailureMechanism(targetData); return ReferenceEquals(sourceFailureMechanism, targetFailureMechanism); } private static PipingFailureMechanism GetParentFailureMechanism(object data) { var calculationContext = data as PipingCalculationContext; if (calculationContext != null) { return calculationContext.PipingFailureMechanism; } var groupContext = data as PipingCalculationGroupContext; if (groupContext != null) { return groupContext.PipingFailureMechanism; } return null; } private void PipingCalculationGroupContextOnDrop(object droppedData, object newParentData, object oldParentData, int position, TreeViewControl treeViewControl) { IPipingCalculationItem pipingCalculationItem = GetAsIPipingCalculationItem(droppedData); var originalOwnerContext = oldParentData as PipingCalculationGroupContext; var target = newParentData as PipingCalculationGroupContext; if (pipingCalculationItem != null && originalOwnerContext != null && target != null) { var isMoveWithinSameContainer = ReferenceEquals(originalOwnerContext, target); DroppingPipingCalculationInContainerStrategy dropHandler = GetDragDropStrategy(isMoveWithinSameContainer, originalOwnerContext, target); dropHandler.Execute(droppedData, pipingCalculationItem, position, treeViewControl); } } private DroppingPipingCalculationInContainerStrategy GetDragDropStrategy(bool isMoveWithinSameContainer, PipingCalculationGroupContext originalOwnerContext, PipingCalculationGroupContext target) { if (isMoveWithinSameContainer) { return new DroppingPipingCalculationWithinSameContainer(originalOwnerContext, target); } return new DroppingPipingCalculationToNewContainer(originalOwnerContext, target); } #region Nested Types: DroppingPipingCalculationInContainerStrategy and implementations /// /// Strategy pattern implementation for dealing with drag & dropping a /// onto data. /// private abstract class DroppingPipingCalculationInContainerStrategy { protected readonly PipingCalculationGroupContext target; private readonly PipingCalculationGroupContext originalOwnerContext; protected DroppingPipingCalculationInContainerStrategy(PipingCalculationGroupContext originalOwnerContext, PipingCalculationGroupContext target) { this.originalOwnerContext = originalOwnerContext; this.target = target; } /// /// Perform the drag & drop operation. /// /// The dragged data. /// The piping calculation item wrapped by . /// The index of the new position within the new owner's collection. /// The tree view control which is at stake. public virtual void Execute(object draggedData, IPipingCalculationItem pipingCalculationItem, int newPosition, TreeViewControl treeViewControl) { MoveCalculationItemToNewOwner(pipingCalculationItem, 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(IPipingCalculationItem pipingCalculationItem, int position) { originalOwnerContext.WrappedData.Children.Remove(pipingCalculationItem); target.WrappedData.Children.Insert(position, pipingCalculationItem); } /// /// Notifies observers of the change in state. /// protected virtual void NotifyObservers() { originalOwnerContext.NotifyObservers(); } } /// /// Strategy implementation for rearranging the order of an /// within a through a drag & drop action. /// private class DroppingPipingCalculationWithinSameContainer : DroppingPipingCalculationInContainerStrategy { /// /// Initializes a new instance of the class. /// /// The calculation group context that is /// the original owner of the dragged item. /// The calculation group context that is the target /// of the drag & drop operation. public DroppingPipingCalculationWithinSameContainer(PipingCalculationGroupContext originalOwnerContext, PipingCalculationGroupContext target) : base(originalOwnerContext, target) {} } /// /// Strategy implementation for moving an from /// one to another using a drag & drop action. /// private class DroppingPipingCalculationToNewContainer : DroppingPipingCalculationInContainerStrategy { /// /// Initializes a new instance of the class. /// /// The calculation group context that is /// the original owner of the dragged item. /// The calculation group context that is the target /// of the drag & drop operation. public DroppingPipingCalculationToNewContainer(PipingCalculationGroupContext originalOwnerContext, PipingCalculationGroupContext target) : base(originalOwnerContext, target) {} public override void Execute(object draggedData, IPipingCalculationItem pipingCalculationItem, int newPosition, TreeViewControl treeViewControl) { MoveCalculationItemToNewOwner(pipingCalculationItem, newPosition); NotifyObservers(); // Try to start a name edit action when an item with the same name was already present if (target.WrappedData.Children.Except(new[] { pipingCalculationItem }).Any(c => c.Name.Equals(pipingCalculationItem.Name))) { treeViewControl.TryRenameNodeForData(draggedData); } } protected override void NotifyObservers() { base.NotifyObservers(); target.NotifyObservers(); } } # endregion # endregion } }