diff --git a/BasicRdl/BasicRdl.csproj b/BasicRdl/BasicRdl.csproj index b427804af..49b7887bd 100644 --- a/BasicRdl/BasicRdl.csproj +++ b/BasicRdl/BasicRdl.csproj @@ -49,127 +49,127 @@ runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime diff --git a/CDP4Addin/CDP4Addin.csproj b/CDP4Addin/CDP4Addin.csproj index 169a218bf..6f099ead9 100644 --- a/CDP4Addin/CDP4Addin.csproj +++ b/CDP4Addin/CDP4Addin.csproj @@ -38,38 +38,38 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CDP4BudgetViewer/CDP4Budget.csproj b/CDP4BudgetViewer/CDP4Budget.csproj index 6c156235a..87d085926 100644 --- a/CDP4BudgetViewer/CDP4Budget.csproj +++ b/CDP4BudgetViewer/CDP4Budget.csproj @@ -41,100 +41,100 @@ runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime diff --git a/CDP4BuiltInRules/CDP4BuiltInRules.csproj b/CDP4BuiltInRules/CDP4BuiltInRules.csproj index 4d9f33438..9d4090c3a 100644 --- a/CDP4BuiltInRules/CDP4BuiltInRules.csproj +++ b/CDP4BuiltInRules/CDP4BuiltInRules.csproj @@ -46,127 +46,127 @@ runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime diff --git a/CDP4Composition.Tests/DragDrop/ElementUsageDropValidatorTestFixture.cs b/CDP4Composition.Tests/DragDrop/ElementUsageDropValidatorTestFixture.cs new file mode 100644 index 000000000..6f0f0499c --- /dev/null +++ b/CDP4Composition.Tests/DragDrop/ElementUsageDropValidatorTestFixture.cs @@ -0,0 +1,144 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2015-2026 Starion Group S.A. +// +// Author: Sam Gerené, Alex Vorobiev, Alexander van Delft, Nathanael Smiechowski, Antoine Théate, Rowan de Voogt +// +// This file is part of CDP4-COMET IME Community Edition. +// The CDP4-COMET IME Community Edition is the Starion Concurrent Design Desktop Application and Excel Integration +// compliant with ECSS-E-TM-10-25 Annex A and Annex C. +// +// The CDP4-COMET IME Community Edition is free software; you can redistribute it and/or +// modify it under the terms of the GNU Affero General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or any later version. +// +// The CDP4-COMET IME Community Edition 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see http://www.gnu.org/licenses/. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace CDP4Composition.Tests.DragDrop +{ + using System; + using System.Windows; + + using CDP4Common.CommonData; + using CDP4Common.EngineeringModelData; + + using CDP4Composition.DragDrop; + + using CDP4Dal.Permission; + + using Moq; + + using NUnit.Framework; + + /// + /// Suite of tests for the class. + /// + [TestFixture] + public class ElementUsageDropValidatorTestFixture + { + private Mock permissionService; + private Iteration iteration; + private ElementDefinition sourceDefinition; + private ElementDefinition targetDefinition; + private ElementDefinition referencedDefinition; + private ElementUsage elementUsage; + + [SetUp] + public void SetUp() + { + this.permissionService = new Mock(); + this.permissionService.Setup(x => x.CanWrite(It.IsAny(), It.IsAny())).Returns(true); + + var engineeringModel = new EngineeringModel(Guid.NewGuid(), null, null); + this.iteration = new Iteration(Guid.NewGuid(), null, null); + engineeringModel.Iteration.Add(this.iteration); + + this.sourceDefinition = new ElementDefinition(Guid.NewGuid(), null, null); + this.targetDefinition = new ElementDefinition(Guid.NewGuid(), null, null); + this.referencedDefinition = new ElementDefinition(Guid.NewGuid(), null, null); + this.iteration.Element.Add(this.sourceDefinition); + this.iteration.Element.Add(this.targetDefinition); + this.iteration.Element.Add(this.referencedDefinition); + + this.elementUsage = new ElementUsage(Guid.NewGuid(), null, null) { ElementDefinition = this.referencedDefinition }; + this.sourceDefinition.ContainedElement.Add(this.elementUsage); + } + + [Test] + public void VerifyThatDroppingOnAnotherDefinitionReturnsMove() + { + var effect = ElementUsageDropValidator.GetDropEffect(this.elementUsage, this.targetDefinition, this.permissionService.Object); + + Assert.That(effect, Is.EqualTo(DragDropEffects.Move)); + } + + [Test] + public void VerifyThatMovingOntoTheCurrentContainerReturnsNone() + { + var effect = ElementUsageDropValidator.GetDropEffect(this.elementUsage, this.sourceDefinition, this.permissionService.Object); + + Assert.That(effect, Is.EqualTo(DragDropEffects.None)); + } + + [Test] + public void VerifyThatDroppingOntoTheReferencedDefinitionReturnsNone() + { + // the usage references referencedDefinition; dropping it there would create a self-containment loop + var moveEffect = ElementUsageDropValidator.GetDropEffect(this.elementUsage, this.referencedDefinition, this.permissionService.Object); + + Assert.That(moveEffect, Is.EqualTo(DragDropEffects.None)); + } + + [Test] + public void VerifyThatContainmentLoopReturnsNone() + { + // referencedDefinition (the usage's type) already uses targetDefinition -> re-parenting there would create a loop + var loopUsage = new ElementUsage(Guid.NewGuid(), null, null) { ElementDefinition = this.targetDefinition }; + this.referencedDefinition.ContainedElement.Add(loopUsage); + + var effect = ElementUsageDropValidator.GetDropEffect(this.elementUsage, this.targetDefinition, this.permissionService.Object); + + Assert.That(effect, Is.EqualTo(DragDropEffects.None)); + } + + [Test] + public void VerifyThatMissingPermissionReturnsNone() + { + this.permissionService.Setup(x => x.CanWrite(It.IsAny(), It.IsAny())).Returns(false); + + var effect = ElementUsageDropValidator.GetDropEffect(this.elementUsage, this.targetDefinition, this.permissionService.Object); + + Assert.That(effect, Is.EqualTo(DragDropEffects.None)); + } + + [Test] + public void VerifyThatDifferentModelReturnsNone() + { + var otherModel = new EngineeringModel(Guid.NewGuid(), null, null); + var otherIteration = new Iteration(Guid.NewGuid(), null, null); + otherModel.Iteration.Add(otherIteration); + var foreignDefinition = new ElementDefinition(Guid.NewGuid(), null, null); + otherIteration.Element.Add(foreignDefinition); + + var effect = ElementUsageDropValidator.GetDropEffect(this.elementUsage, foreignDefinition, this.permissionService.Object); + + Assert.That(effect, Is.EqualTo(DragDropEffects.None)); + } + + [Test] + public void VerifyThatNullArgumentsReturnNone() + { + Assert.That(ElementUsageDropValidator.GetDropEffect(null, this.targetDefinition, this.permissionService.Object), Is.EqualTo(DragDropEffects.None)); + Assert.That(ElementUsageDropValidator.GetDropEffect(this.elementUsage, null, this.permissionService.Object), Is.EqualTo(DragDropEffects.None)); + } + } +} diff --git a/CDP4Composition/CDP4Composition.csproj b/CDP4Composition/CDP4Composition.csproj index 80337fbc6..7666b5f68 100644 --- a/CDP4Composition/CDP4Composition.csproj +++ b/CDP4Composition/CDP4Composition.csproj @@ -35,38 +35,38 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CDP4Composition/DragDrop/ElementUsageDropValidator.cs b/CDP4Composition/DragDrop/ElementUsageDropValidator.cs new file mode 100644 index 000000000..7092b8053 --- /dev/null +++ b/CDP4Composition/DragDrop/ElementUsageDropValidator.cs @@ -0,0 +1,84 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2015-2026 Starion Group S.A. +// +// Author: Sam Gerené, Alex Vorobiev, Alexander van Delft, Nathanael Smiechowski, Antoine Théate, Rowan de Voogt +// +// This file is part of CDP4-COMET IME Community Edition. +// The CDP4-COMET IME Community Edition is the Starion Concurrent Design Desktop Application and Excel Integration +// compliant with ECSS-E-TM-10-25 Annex A and Annex C. +// +// The CDP4-COMET IME Community Edition is free software; you can redistribute it and/or +// modify it under the terms of the GNU Affero General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or any later version. +// +// The CDP4-COMET IME Community Edition 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see http://www.gnu.org/licenses/. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace CDP4Composition.DragDrop +{ + using System.Windows; + + using CDP4Common.CommonData; + using CDP4Common.EngineeringModelData; + + using CDP4Dal.Permission; + + /// + /// Centralizes the validation of dropping an onto an , so that the + /// move (re-parent) drag-and-drop behaviour stays consistent - and safe against invalid models - across the Element Definitions + /// browser and the Product Tree. + /// + public static class ElementUsageDropValidator + { + /// + /// Computes the for dropping an onto an + /// to move (re-parent) it. + /// + /// The being dragged. + /// The that is the drop target. + /// The used to check write permission. + /// The resulting . + public static DragDropEffects GetDropEffect(ElementUsage elementUsage, ElementDefinition targetElementDefinition, IPermissionService permissionService) + { + if (elementUsage == null || targetElementDefinition == null) + { + return DragDropEffects.None; + } + + // permission to move an element usage into the target definition + if (!permissionService.CanWrite(ClassKind.ElementUsage, targetElementDefinition)) + { + return DragDropEffects.None; + } + + // moving between models is not supported + if (elementUsage.TopContainer != targetElementDefinition.TopContainer) + { + return DragDropEffects.None; + } + + // dropping the usage onto the definition it references, or onto a definition already used inside it, would create a containment loop + if (elementUsage.ElementDefinition.HasUsageOf(targetElementDefinition)) + { + return DragDropEffects.None; + } + + // a move onto the usage's current container would be a no-op + if (elementUsage.Container == targetElementDefinition) + { + return DragDropEffects.None; + } + + return DragDropEffects.Move; + } + } +} diff --git a/CDP4Composition/Services/IThingCreator.cs b/CDP4Composition/Services/IThingCreator.cs index e7102f1de..b066e6fb6 100644 --- a/CDP4Composition/Services/IThingCreator.cs +++ b/CDP4Composition/Services/IThingCreator.cs @@ -84,6 +84,21 @@ public interface IThingCreator /// Task CreateElementUsage(ElementDefinition container, ElementDefinition referencedDefinition, DomainOfExpertise owner, ISession session); + /// + /// Moves an existing into another , preserving all of its properties + /// (name, short-name, owner, excluded options and contained s). + /// + /// + /// The that is to be moved. + /// + /// + /// The that becomes the new container of the . + /// + /// + /// The in which the move is performed. + /// + Task MoveElementUsage(ElementUsage elementUsage, ElementDefinition targetElementDefinition, ISession session); + /// /// Method for creating a for requirement verification between a and a . /// diff --git a/CDP4Composition/Services/ThingCreator.cs b/CDP4Composition/Services/ThingCreator.cs index d0532868c..7ccc2e5a2 100644 --- a/CDP4Composition/Services/ThingCreator.cs +++ b/CDP4Composition/Services/ThingCreator.cs @@ -269,7 +269,58 @@ public async Task CreateElementUsage(ElementDefinition container, ElementDefinit { logger.Error(ex, "The ElementUsage could not be created"); throw; - } + } + } + + /// + /// Moves an existing into another , preserving all of its properties. + /// + /// + /// The that is to be moved. + /// + /// + /// The that becomes the new container of the . + /// + /// + /// The in which the move is performed. + /// + public async Task MoveElementUsage(ElementUsage elementUsage, ElementDefinition targetElementDefinition, ISession session) + { + if (elementUsage == null) + { + throw new ArgumentNullException(nameof(elementUsage), "The elementUsage must not be null"); + } + + if (targetElementDefinition == null) + { + throw new ArgumentNullException(nameof(targetElementDefinition), "The targetElementDefinition must not be null"); + } + + if (session == null) + { + throw new ArgumentNullException(nameof(session), "The session may not be null"); + } + + // re-parent the usage by adding it to the target definition; the same pattern is used to move a Requirement between specifications. + var transactionContext = TransactionContextResolver.ResolveContext(targetElementDefinition); + var transaction = new ThingTransaction(transactionContext); + + var usageClone = elementUsage.Clone(false); + transaction.CreateOrUpdate(usageClone); + + var elementDefinitionClone = targetElementDefinition.Clone(false); + elementDefinitionClone.ContainedElement.Add(usageClone); + transaction.CreateOrUpdate(elementDefinitionClone); + + try + { + await session.Write(transaction.FinalizeTransaction()); + } + catch (Exception ex) + { + logger.Error(ex, "The ElementUsage could not be moved"); + throw; + } } /// diff --git a/CDP4CrossViewEditor/CDP4CrossViewEditor.csproj b/CDP4CrossViewEditor/CDP4CrossViewEditor.csproj index 42389ea8d..e7284233c 100644 --- a/CDP4CrossViewEditor/CDP4CrossViewEditor.csproj +++ b/CDP4CrossViewEditor/CDP4CrossViewEditor.csproj @@ -45,100 +45,100 @@ runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime diff --git a/CDP4Dashboard/CDP4Dashboard.csproj b/CDP4Dashboard/CDP4Dashboard.csproj index 3e9bed56e..cf4731e4c 100644 --- a/CDP4Dashboard/CDP4Dashboard.csproj +++ b/CDP4Dashboard/CDP4Dashboard.csproj @@ -37,127 +37,127 @@ runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime diff --git a/CDP4IME/COMET-CE.csproj b/CDP4IME/COMET-CE.csproj index 826406942..b9cd2fa55 100644 --- a/CDP4IME/COMET-CE.csproj +++ b/CDP4IME/COMET-CE.csproj @@ -49,55 +49,55 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CDP4LogInfo/CDP4LogInfo.csproj b/CDP4LogInfo/CDP4LogInfo.csproj index 7a8741d54..4f75e1af6 100644 --- a/CDP4LogInfo/CDP4LogInfo.csproj +++ b/CDP4LogInfo/CDP4LogInfo.csproj @@ -51,100 +51,100 @@ runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime diff --git a/CDP4ObjectBrowser/CDP4ObjectBrowser.csproj b/CDP4ObjectBrowser/CDP4ObjectBrowser.csproj index 0c1418eee..707f496b8 100644 --- a/CDP4ObjectBrowser/CDP4ObjectBrowser.csproj +++ b/CDP4ObjectBrowser/CDP4ObjectBrowser.csproj @@ -45,100 +45,100 @@ runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime diff --git a/CDP4ParameterSheetGenerator/CDP4ParameterSheetGenerator.csproj b/CDP4ParameterSheetGenerator/CDP4ParameterSheetGenerator.csproj index eee087210..9bb2ff2e0 100644 --- a/CDP4ParameterSheetGenerator/CDP4ParameterSheetGenerator.csproj +++ b/CDP4ParameterSheetGenerator/CDP4ParameterSheetGenerator.csproj @@ -45,100 +45,100 @@ runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime diff --git a/CDP4PropertyGrid/CDP4PropertyGrid.csproj b/CDP4PropertyGrid/CDP4PropertyGrid.csproj index 8c0aaf880..ab780d76a 100644 --- a/CDP4PropertyGrid/CDP4PropertyGrid.csproj +++ b/CDP4PropertyGrid/CDP4PropertyGrid.csproj @@ -45,100 +45,100 @@ runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime diff --git a/CDP4ReferenceDataMapper/CDP4ReferenceDataMapper.csproj b/CDP4ReferenceDataMapper/CDP4ReferenceDataMapper.csproj index 05733f613..268a2a619 100644 --- a/CDP4ReferenceDataMapper/CDP4ReferenceDataMapper.csproj +++ b/CDP4ReferenceDataMapper/CDP4ReferenceDataMapper.csproj @@ -48,100 +48,100 @@ runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime diff --git a/CDP4RelationshipEditor/CDP4RelationshipEditor.csproj b/CDP4RelationshipEditor/CDP4RelationshipEditor.csproj index 6c4bf1b43..33939ebc5 100644 --- a/CDP4RelationshipEditor/CDP4RelationshipEditor.csproj +++ b/CDP4RelationshipEditor/CDP4RelationshipEditor.csproj @@ -48,100 +48,100 @@ runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime diff --git a/CDP4Reporting.Tests/CDP4Reporting.Tests.csproj b/CDP4Reporting.Tests/CDP4Reporting.Tests.csproj index b00b0a1eb..0f47cb380 100644 --- a/CDP4Reporting.Tests/CDP4Reporting.Tests.csproj +++ b/CDP4Reporting.Tests/CDP4Reporting.Tests.csproj @@ -34,8 +34,8 @@ - - + + diff --git a/CDP4Reporting/CDP4Reporting.csproj b/CDP4Reporting/CDP4Reporting.csproj index c5dde887f..d5b71ebb4 100644 --- a/CDP4Reporting/CDP4Reporting.csproj +++ b/CDP4Reporting/CDP4Reporting.csproj @@ -60,127 +60,127 @@ runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime diff --git a/CDP4Scripting/CDP4Scripting.csproj b/CDP4Scripting/CDP4Scripting.csproj index 0c5d76ecd..05bc7e3c9 100644 --- a/CDP4Scripting/CDP4Scripting.csproj +++ b/CDP4Scripting/CDP4Scripting.csproj @@ -52,100 +52,100 @@ runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime diff --git a/CDP4ShellDialogs/CDP4ShellDialogs.csproj b/CDP4ShellDialogs/CDP4ShellDialogs.csproj index 9c335ddfa..05d8e5273 100644 --- a/CDP4ShellDialogs/CDP4ShellDialogs.csproj +++ b/CDP4ShellDialogs/CDP4ShellDialogs.csproj @@ -44,38 +44,38 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CDP4SiteDirectory/CDP4SiteDirectory.csproj b/CDP4SiteDirectory/CDP4SiteDirectory.csproj index 7b4417ac7..42f84ad9e 100644 --- a/CDP4SiteDirectory/CDP4SiteDirectory.csproj +++ b/CDP4SiteDirectory/CDP4SiteDirectory.csproj @@ -49,100 +49,100 @@ runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime diff --git a/EngineeringModel.Tests/Utilities/ThingCreatorTestFixture.cs b/EngineeringModel.Tests/Utilities/ThingCreatorTestFixture.cs index d36c23b53..cd061c066 100644 --- a/EngineeringModel.Tests/Utilities/ThingCreatorTestFixture.cs +++ b/EngineeringModel.Tests/Utilities/ThingCreatorTestFixture.cs @@ -227,5 +227,63 @@ public void VerifyThatExceptionIsThrownWhenCreateElementUsageFails() Assert.ThrowsAsync(async () => await this.thingCreator.CreateElementUsage(elementDefinitionA, elementDefinitionB, domainOfExpertise, this.sessionThatThrowsException.Object)); } + + [Test] + public async Task VerifyThatMoveElementUsageExecutesWrite() + { + var elementUsage = this.SetupElementUsageToRelocate(out var targetDefinition); + + await this.thingCreator.MoveElementUsage(elementUsage, targetDefinition, this.session.Object); + + this.session.Verify(x => x.Write(It.IsAny())); + } + + [Test] + public void VerifyThatArgumentNullExceptionsAreThrownOnMoveElementUsage() + { + var elementUsage = this.SetupElementUsageToRelocate(out var targetDefinition); + + Assert.ThrowsAsync(async () => await this.thingCreator.MoveElementUsage(null, targetDefinition, this.session.Object)); + Assert.ThrowsAsync(async () => await this.thingCreator.MoveElementUsage(elementUsage, null, this.session.Object)); + Assert.ThrowsAsync(async () => await this.thingCreator.MoveElementUsage(elementUsage, targetDefinition, null)); + } + + [Test] + public void VerifyThatExceptionIsThrownWhenMoveElementUsageFails() + { + var elementUsage = this.SetupElementUsageToRelocate(out var targetDefinition); + + Assert.ThrowsAsync(async () => await this.thingCreator.MoveElementUsage(elementUsage, targetDefinition, this.sessionThatThrowsException.Object)); + } + + /// + /// Builds a model with a source and a target and an contained by + /// the source that references a third . + /// + /// The target to move the usage into. + /// The to relocate. + private ElementUsage SetupElementUsageToRelocate(out ElementDefinition targetDefinition) + { + var domainOfExpertise = new DomainOfExpertise(Guid.NewGuid(), this.cache, null); + var engineeringModel = new EngineeringModel(Guid.NewGuid(), this.cache, null); + var iteration = new Iteration(Guid.NewGuid(), this.cache, null); + engineeringModel.Iteration.Add(iteration); + + var sourceDefinition = new ElementDefinition(Guid.NewGuid(), this.cache, null) { Owner = domainOfExpertise }; + targetDefinition = new ElementDefinition(Guid.NewGuid(), this.cache, null) { Owner = domainOfExpertise }; + var referencedDefinition = new ElementDefinition(Guid.NewGuid(), this.cache, null) { Owner = domainOfExpertise }; + + iteration.Element.Add(sourceDefinition); + iteration.Element.Add(targetDefinition); + iteration.Element.Add(referencedDefinition); + + var elementUsage = new ElementUsage(Guid.NewGuid(), this.cache, null) { Owner = domainOfExpertise, ElementDefinition = referencedDefinition, Name = "usage", ShortName = "usage" }; + sourceDefinition.ContainedElement.Add(elementUsage); + + // the usage must be cache-resident, as it always is at runtime + this.cache.TryAdd(new CacheKey(elementUsage.Iid, iteration.Iid), new Lazy(() => elementUsage)); + + return elementUsage; + } } -} \ No newline at end of file +} diff --git a/EngineeringModel.Tests/ViewModels/ElementDefinitionTreeRows/ElementDefinitionRowViewModelTestFixture.cs b/EngineeringModel.Tests/ViewModels/ElementDefinitionTreeRows/ElementDefinitionRowViewModelTestFixture.cs index 167603ad8..6c78ce698 100644 --- a/EngineeringModel.Tests/ViewModels/ElementDefinitionTreeRows/ElementDefinitionRowViewModelTestFixture.cs +++ b/EngineeringModel.Tests/ViewModels/ElementDefinitionTreeRows/ElementDefinitionRowViewModelTestFixture.cs @@ -242,6 +242,119 @@ public void VerifyThatExceptionIsCaughtWhenElementUsageCouldNotBeCreatedOnDrop() Assert.AreEqual("The Element Usage could not be created", row.ErrorMsg); } + [Test] + public void VerifyThatDragElementUsageSetsMoveEffect() + { + this.permissionService.Setup(x => x.CanWrite(It.IsAny(), It.IsAny())).Returns(true); + + var domainOfExpertise = new DomainOfExpertise(Guid.NewGuid(), this.assembler.Cache, this.uri); + + var sourceDefinition = new ElementDefinition(Guid.NewGuid(), this.assembler.Cache, this.uri) { Owner = domainOfExpertise }; + var targetDefinition = new ElementDefinition(Guid.NewGuid(), this.assembler.Cache, this.uri) { Owner = domainOfExpertise }; + var referencedDefinition = new ElementDefinition(Guid.NewGuid(), this.assembler.Cache, this.uri) { Owner = domainOfExpertise }; + this.iteration.Element.Add(sourceDefinition); + this.iteration.Element.Add(targetDefinition); + this.iteration.Element.Add(referencedDefinition); + + var elementUsage = new ElementUsage(Guid.NewGuid(), this.assembler.Cache, this.uri) { Owner = domainOfExpertise, ElementDefinition = referencedDefinition, Name = "usage", ShortName = "usage" }; + sourceDefinition.ContainedElement.Add(elementUsage); + + var row = new ElementDefinitionRowViewModel(targetDefinition, domainOfExpertise, this.session.Object, null, this.obfuscationService.Object); + + var dropInfo = new Mock(); + dropInfo.Setup(x => x.Payload).Returns(elementUsage); + dropInfo.SetupProperty(x => x.Effects); + + row.DragOver(dropInfo.Object); + + Assert.That(dropInfo.Object.Effects, Is.EqualTo(DragDropEffects.Move)); + } + + [Test] + public void VerifyThatElementUsageGetsMovedToAnotherElementDefinitionOnDrop() + { + this.permissionService.Setup(x => x.CanWrite(It.IsAny(), It.IsAny())).Returns(true); + + var domainOfExpertise = new DomainOfExpertise(Guid.NewGuid(), this.assembler.Cache, this.uri); + + var sourceDefinition = new ElementDefinition(Guid.NewGuid(), this.assembler.Cache, this.uri) { Owner = domainOfExpertise }; + var targetDefinition = new ElementDefinition(Guid.NewGuid(), this.assembler.Cache, this.uri) { Owner = domainOfExpertise }; + var referencedDefinition = new ElementDefinition(Guid.NewGuid(), this.assembler.Cache, this.uri) { Owner = domainOfExpertise }; + this.iteration.Element.Add(sourceDefinition); + this.iteration.Element.Add(targetDefinition); + this.iteration.Element.Add(referencedDefinition); + + var elementUsage = new ElementUsage(Guid.NewGuid(), this.assembler.Cache, this.uri) { Owner = domainOfExpertise, ElementDefinition = referencedDefinition, Name = "usage", ShortName = "usage" }; + sourceDefinition.ContainedElement.Add(elementUsage); + + var row = new ElementDefinitionRowViewModel(targetDefinition, domainOfExpertise, this.session.Object, null, this.obfuscationService.Object); + row.ThingCreator = this.thingCreator.Object; + + var dropInfo = new Mock(); + dropInfo.Setup(x => x.Payload).Returns(elementUsage); + dropInfo.SetupProperty(x => x.Effects); + + row.DragOver(dropInfo.Object); + Assert.That(dropInfo.Object.Effects, Is.EqualTo(DragDropEffects.Move)); + + row.Drop(dropInfo.Object); + + this.thingCreator.Verify(x => x.MoveElementUsage(elementUsage, targetDefinition, this.session.Object)); + } + + [Test] + public void VerifyThatDragElementUsageOntoItsReferencedDefinitionSetsNoneEffect() + { + this.permissionService.Setup(x => x.CanWrite(It.IsAny(), It.IsAny())).Returns(true); + + var domainOfExpertise = new DomainOfExpertise(Guid.NewGuid(), this.assembler.Cache, this.uri); + + var sourceDefinition = new ElementDefinition(Guid.NewGuid(), this.assembler.Cache, this.uri) { Owner = domainOfExpertise }; + var referencedDefinition = new ElementDefinition(Guid.NewGuid(), this.assembler.Cache, this.uri) { Owner = domainOfExpertise }; + this.iteration.Element.Add(sourceDefinition); + this.iteration.Element.Add(referencedDefinition); + + var elementUsage = new ElementUsage(Guid.NewGuid(), this.assembler.Cache, this.uri) { Owner = domainOfExpertise, ElementDefinition = referencedDefinition }; + sourceDefinition.ContainedElement.Add(elementUsage); + + // dropping the usage back onto the definition it references would create a containment loop + var row = new ElementDefinitionRowViewModel(referencedDefinition, domainOfExpertise, this.session.Object, null, this.obfuscationService.Object); + + var dropInfo = new Mock(); + dropInfo.Setup(x => x.Payload).Returns(elementUsage); + dropInfo.SetupProperty(x => x.Effects); + + row.DragOver(dropInfo.Object); + + Assert.That(dropInfo.Object.Effects, Is.EqualTo(DragDropEffects.None)); + } + + [Test] + public void VerifyThatDragElementUsageOntoItsCurrentContainerSetsNoneEffect() + { + this.permissionService.Setup(x => x.CanWrite(It.IsAny(), It.IsAny())).Returns(true); + + var domainOfExpertise = new DomainOfExpertise(Guid.NewGuid(), this.assembler.Cache, this.uri); + + var sourceDefinition = new ElementDefinition(Guid.NewGuid(), this.assembler.Cache, this.uri) { Owner = domainOfExpertise }; + var referencedDefinition = new ElementDefinition(Guid.NewGuid(), this.assembler.Cache, this.uri) { Owner = domainOfExpertise }; + this.iteration.Element.Add(sourceDefinition); + this.iteration.Element.Add(referencedDefinition); + + var elementUsage = new ElementUsage(Guid.NewGuid(), this.assembler.Cache, this.uri) { Owner = domainOfExpertise, ElementDefinition = referencedDefinition }; + sourceDefinition.ContainedElement.Add(elementUsage); + + var row = new ElementDefinitionRowViewModel(sourceDefinition, domainOfExpertise, this.session.Object, null, this.obfuscationService.Object); + + var dropInfo = new Mock(); + dropInfo.Setup(x => x.Payload).Returns(elementUsage); + dropInfo.SetupProperty(x => x.Effects); + + row.DragOver(dropInfo.Object); + + Assert.That(dropInfo.Object.Effects, Is.EqualTo(DragDropEffects.None)); + } + [Test] public void VerifyThatDragCategorySetsCopyEffectAndCanBeDropped() { @@ -495,6 +608,17 @@ public Task CreateElementUsage( throw new Exception("The Element Usage could not be created"); } + /// + /// Moves an existing into another + /// + /// The that is to be moved. + /// The that becomes the new container. + /// The in which the move is performed. + public Task MoveElementUsage(ElementUsage elementUsage, ElementDefinition targetElementDefinition, ISession session) + { + throw new Exception("The Element Usage could not be moved"); + } + /// /// Method for creating a between a and a . /// diff --git a/EngineeringModel/EngineeringModel.csproj b/EngineeringModel/EngineeringModel.csproj index 6e6332042..d887d2c18 100644 --- a/EngineeringModel/EngineeringModel.csproj +++ b/EngineeringModel/EngineeringModel.csproj @@ -52,100 +52,100 @@ runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime diff --git a/EngineeringModel/ViewModels/ElementDefinitionBrowser/ElementDefinitionTreeRows/ElementDefinitionRowViewModel.cs b/EngineeringModel/ViewModels/ElementDefinitionBrowser/ElementDefinitionTreeRows/ElementDefinitionRowViewModel.cs index 2cce4248a..2844a1e2e 100644 --- a/EngineeringModel/ViewModels/ElementDefinitionBrowser/ElementDefinitionTreeRows/ElementDefinitionRowViewModel.cs +++ b/EngineeringModel/ViewModels/ElementDefinitionBrowser/ElementDefinitionTreeRows/ElementDefinitionRowViewModel.cs @@ -234,6 +234,12 @@ public void DragOver(IDropInfo dropInfo) return; } + if (dropInfo.Payload is ElementUsage elementUsage) + { + this.DragOver(dropInfo, elementUsage); + return; + } + if (dropInfo.Payload is ElementDefinition elementDefinition) { this.DragOver(dropInfo, elementDefinition); @@ -283,12 +289,17 @@ public async Task Drop(IDropInfo dropInfo) } } + if (dropInfo.Payload is ElementUsage elementUsage) + { + await this.Drop(dropInfo, elementUsage); + } + if (dropInfo.Payload is ElementDefinition elementDefinition) { await this.Drop(dropInfo, elementDefinition); } - // moving + // moving if (dropInfo.Payload is Parameter parameter) { await this.Drop(dropInfo, parameter); @@ -413,6 +424,8 @@ protected override void UpdateDetails() sb.AppendLine(); sb.AppendLine("NOTE: The Element Definition is always copied, including the contained Element Usages and Parameters."); sb.AppendLine("NOTE: This functionality is only supported if the target server is COMET."); + sb.AppendLine(); + sb.AppendLine("An Element Usage dragged onto an Element Definition is moved into it, keeping its name, short-name, owner and parameter overrides."); this.Details = sb.ToString(); } @@ -632,6 +645,40 @@ private async Task Drop(IDropInfo dropInfo, ElementDefinition elementDefinition) } } + /// + /// Set the when the payload is an + /// + /// The + /// The in the payload + private void DragOver(IDropInfo dropinfo, ElementUsage elementUsage) + { + dropinfo.Effects = ElementUsageDropValidator.GetDropEffect(elementUsage, this.Thing, this.PermissionService); + } + + /// + /// Handle the drop of an by moving it into this , + /// preserving its name, short-name, owner and contained s. + /// + /// The containing the payload + /// The + private async Task Drop(IDropInfo dropInfo, ElementUsage elementUsage) + { + if (dropInfo.Effects != DragDropEffects.Move) + { + return; + } + + try + { + await this.ThingCreator.MoveElementUsage(elementUsage, this.Thing, this.Session); + } + catch (Exception ex) + { + logger.Error(ex.Message); + this.ErrorMsg = ex.Message; + } + } + /// /// Handle the drop of a /// diff --git a/ProductTree.Tests/ProductTreeRows/ElementDefinitionRowViewModelTestFixture.cs b/ProductTree.Tests/ProductTreeRows/ElementDefinitionRowViewModelTestFixture.cs index d05ed24da..289d715bc 100644 --- a/ProductTree.Tests/ProductTreeRows/ElementDefinitionRowViewModelTestFixture.cs +++ b/ProductTree.Tests/ProductTreeRows/ElementDefinitionRowViewModelTestFixture.cs @@ -76,9 +76,11 @@ public class ElementDefinitionRowViewModelTestFixture private Option option; private ElementDefinition elementDef; private ElementDefinition elementDef2; + private ElementDefinition elementDef3; private Category category; private DomainOfExpertise domain; private ElementUsage elementUsage; + private ElementUsage elementUsage2; private ConcurrentDictionary> cache = new ConcurrentDictionary>(); private readonly string nestedElementPath = "PATH"; @@ -120,6 +122,9 @@ public void Setup() this.elementDef2 = new ElementDefinition(Guid.NewGuid(), this.cache, this.uri) { Owner = this.domain }; this.elementUsage = new ElementUsage(Guid.NewGuid(), this.cache, this.uri) { ElementDefinition = this.elementDef2, Owner = this.domain }; + this.elementDef3 = new ElementDefinition(Guid.NewGuid(), this.cache, this.uri) { Owner = this.domain }; + this.elementUsage2 = new ElementUsage(Guid.NewGuid(), this.cache, this.uri) { ElementDefinition = this.elementDef3, Owner = this.domain }; + this.siteDir.Person.Add(this.person); this.siteDir.Model.Add(this.modelSetup); this.modelSetup.IterationSetup.Add(this.iterationSetup); @@ -133,7 +138,9 @@ public void Setup() this.iteration.TopElement = this.elementDef; this.iteration.Element.Add(this.elementDef); this.iteration.Element.Add(this.elementDef2); + this.iteration.Element.Add(this.elementDef3); this.elementDef.ContainedElement.Add(this.elementUsage); + this.elementDef2.ContainedElement.Add(this.elementUsage2); this.session.Setup(x => x.ActivePerson).Returns(this.person); this.session.Setup(x => x.DataSourceUri).Returns(this.uri.ToString); @@ -355,6 +362,36 @@ public async Task VerifyThatDropWorks() this.thingCreator.Verify(x => x.CreateElementUsage(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())); } + + [Test] + public void VerifyThatDragOverElementUsageSetsMoveEffect() + { + this.permissionService.Setup(x => x.CanWrite(It.IsAny(), It.IsAny())).Returns(true); + var vm = new ElementDefinitionRowViewModel(this.elementDef, this.option, this.session.Object, null); + + var dropinfo = new Mock(); + dropinfo.Setup(x => x.Payload).Returns(this.elementUsage2); + + dropinfo.SetupProperty(x => x.Effects); + vm.DragOver(dropinfo.Object); + + Assert.AreEqual(DragDropEffects.Move, dropinfo.Object.Effects); + } + + [Test] + public async Task VerifyThatDropMovesElementUsage() + { + this.permissionService.Setup(x => x.CanWrite(It.IsAny(), It.IsAny())).Returns(true); + var vm = new ElementDefinitionRowViewModel(this.elementDef, this.option, this.session.Object, null); + + var dropinfo = new Mock(); + dropinfo.Setup(x => x.Payload).Returns(this.elementUsage2); + dropinfo.Setup(x => x.Effects).Returns(DragDropEffects.Move); + + await vm.Drop(dropinfo.Object); + + this.thingCreator.Verify(x => x.MoveElementUsage(this.elementUsage2, this.elementDef, this.session.Object)); + } } /// diff --git a/ProductTree.Tests/ProductTreeRows/ElementUsageRowViewModelTestFixture.cs b/ProductTree.Tests/ProductTreeRows/ElementUsageRowViewModelTestFixture.cs index 9f018d064..d7cd3f793 100644 --- a/ProductTree.Tests/ProductTreeRows/ElementUsageRowViewModelTestFixture.cs +++ b/ProductTree.Tests/ProductTreeRows/ElementUsageRowViewModelTestFixture.cs @@ -84,11 +84,13 @@ internal class ElementUsageRowViewModelTestFixture private ElementDefinition elementDef3; private ElementDefinition elementDef4; private ElementDefinition elementDef5; + private ElementDefinition elementDef6; private DomainOfExpertise domain; private ElementUsage elementUsage; private ElementUsage elementUsage4; private ElementUsage elementUsage5; private ElementUsage elementUsage6; + private ElementUsage elementUsage7; private ParameterValueSet valueSet; private ParameterOverrideValueSet valueSetOverride; @@ -157,6 +159,13 @@ public void Setup() this.elementUsage6 = new ElementUsage(Guid.NewGuid(), this.cache, this.uri) { ElementDefinition = this.elementDef4, Container = this.elementDef5, Owner = this.domain, Name = "Element usage 6", ShortName = "EU6" }; + this.elementDef6 = new ElementDefinition(Guid.NewGuid(), this.cache, this.uri) { Owner = this.domain }; + + this.elementUsage7 = new ElementUsage(Guid.NewGuid(), this.cache, this.uri) + { ElementDefinition = this.elementDef6, Owner = this.domain, Name = "Element usage 7", ShortName = "EU7" }; + + this.elementDef3.ContainedElement.Add(this.elementUsage7); + this.valueSet = new ParameterValueSet(Guid.NewGuid(), this.cache, this.uri); this.valueSet.Published = new ValueArray(new List { "1" }); this.valueSet.Manual = new ValueArray(new List { "1" }); @@ -445,6 +454,36 @@ public async Task VerifyThatDropWorks() this.thingCreator.Verify(x => x.CreateElementUsage(this.elementUsage.ElementDefinition, It.IsAny(), It.IsAny(), It.IsAny())); } + [Test] + public void VerifyThatDragOverElementUsageSetsMoveEffect() + { + this.permissionService.Setup(x => x.CanWrite(It.IsAny(), It.IsAny())).Returns(true); + var vm = new ElementUsageRowViewModel(this.elementUsage, this.option, this.session.Object, null); + + var dropinfo = new Mock(); + dropinfo.Setup(x => x.Payload).Returns(this.elementUsage7); + + dropinfo.SetupProperty(x => x.Effects); + vm.DragOver(dropinfo.Object); + + Assert.AreEqual(DragDropEffects.Move, dropinfo.Object.Effects); + } + + [Test] + public async Task VerifyThatDropMovesElementUsage() + { + this.permissionService.Setup(x => x.CanWrite(It.IsAny(), It.IsAny())).Returns(true); + var vm = new ElementUsageRowViewModel(this.elementUsage, this.option, this.session.Object, null); + + var dropinfo = new Mock(); + dropinfo.Setup(x => x.Payload).Returns(this.elementUsage7); + dropinfo.Setup(x => x.Effects).Returns(DragDropEffects.Move); + + await vm.Drop(dropinfo.Object); + + this.thingCreator.Verify(x => x.MoveElementUsage(this.elementUsage7, this.elementDef2, this.session.Object)); + } + [Test] public void VerifyThatCategoryIsCollectedCorrectlyForElementUsage4() { diff --git a/ProductTree/ProductTree.csproj b/ProductTree/ProductTree.csproj index 962a7fd8b..62bbf617d 100644 --- a/ProductTree/ProductTree.csproj +++ b/ProductTree/ProductTree.csproj @@ -39,100 +39,100 @@ - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime diff --git a/ProductTree/ViewModels/ProductTreeRows/ElementDefinitionRowViewModel.cs b/ProductTree/ViewModels/ProductTreeRows/ElementDefinitionRowViewModel.cs index 09655d88a..f114207d1 100644 --- a/ProductTree/ViewModels/ProductTreeRows/ElementDefinitionRowViewModel.cs +++ b/ProductTree/ViewModels/ProductTreeRows/ElementDefinitionRowViewModel.cs @@ -349,6 +349,12 @@ public void UpdateParameterGroupPosition(ParameterGroup parameterGroup) /// public void DragOver(IDropInfo dropInfo) { + if (dropInfo.Payload is ElementUsage elementUsage) + { + dropInfo.Effects = ElementUsageDropValidator.GetDropEffect(elementUsage, this.Thing, this.PermissionService); + return; + } + if (dropInfo.Payload is ElementDefinition elementDefinition) { this.DragOver(dropInfo, elementDefinition); @@ -366,12 +372,42 @@ public void DragOver(IDropInfo dropInfo) /// public async Task Drop(IDropInfo dropInfo) { + if (dropInfo.Payload is ElementUsage elementUsage) + { + await this.Drop(dropInfo, elementUsage); + return; + } + if (dropInfo.Payload is ElementDefinition elementDefinition) { await this.Drop(dropInfo, elementDefinition); } } + /// + /// Handle the drop of an by moving it into this , + /// preserving its name, short-name, owner and contained s. + /// + /// The containing the payload + /// The + private async Task Drop(IDropInfo dropInfo, ElementUsage elementUsage) + { + if (dropInfo.Effects != DragDropEffects.Move) + { + return; + } + + try + { + await this.ThingCreator.MoveElementUsage(elementUsage, this.Thing, this.Session); + } + catch (Exception ex) + { + logger.Error(ex.Message); + this.ErrorMsg = ex.Message; + } + } + /// /// Update the property /// diff --git a/ProductTree/ViewModels/ProductTreeRows/ElementUsageRowViewModel.cs b/ProductTree/ViewModels/ProductTreeRows/ElementUsageRowViewModel.cs index e4808c396..236c1d0c6 100644 --- a/ProductTree/ViewModels/ProductTreeRows/ElementUsageRowViewModel.cs +++ b/ProductTree/ViewModels/ProductTreeRows/ElementUsageRowViewModel.cs @@ -285,6 +285,12 @@ public void UpdateParameterGroupPosition(ParameterGroup parameterGroup) /// public void DragOver(IDropInfo dropInfo) { + if (dropInfo.Payload is ElementUsage elementUsage) + { + dropInfo.Effects = ElementUsageDropValidator.GetDropEffect(elementUsage, this.Thing.ElementDefinition, this.PermissionService); + return; + } + if (dropInfo.Payload is ElementDefinition elementDefinition) { this.DragOver(dropInfo, elementDefinition); @@ -302,12 +308,42 @@ public void DragOver(IDropInfo dropInfo) /// public async Task Drop(IDropInfo dropInfo) { + if (dropInfo.Payload is ElementUsage elementUsage) + { + await this.Drop(dropInfo, elementUsage); + return; + } + if (dropInfo.Payload is ElementDefinition elementDefinition) { await this.Drop(dropInfo, elementDefinition); } } + /// + /// Handle the drop of an by moving it into the referenced by this + /// usage, preserving its name, short-name, owner and contained s. + /// + /// The containing the payload + /// The + private async Task Drop(IDropInfo dropInfo, ElementUsage elementUsage) + { + if (dropInfo.Effects != DragDropEffects.Move) + { + return; + } + + try + { + await this.ThingCreator.MoveElementUsage(elementUsage, this.Thing.ElementDefinition, this.Session); + } + catch (Exception ex) + { + logger.Error(ex.Message); + this.ErrorMsg = ex.Message; + } + } + /// /// Update the property /// diff --git a/RelationshipMatrix/CDP4RelationshipMatrix.csproj b/RelationshipMatrix/CDP4RelationshipMatrix.csproj index 2dbf0e2a6..ef8e6bb50 100644 --- a/RelationshipMatrix/CDP4RelationshipMatrix.csproj +++ b/RelationshipMatrix/CDP4RelationshipMatrix.csproj @@ -46,100 +46,100 @@ runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime diff --git a/Requirements/Requirements.csproj b/Requirements/Requirements.csproj index 5b14b69ec..595dc6324 100644 --- a/Requirements/Requirements.csproj +++ b/Requirements/Requirements.csproj @@ -57,127 +57,127 @@ runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime - + runtime