Index: Riskeer/Piping/src/Riskeer.Piping.Forms/PropertyClasses/PipingFailureMechanismSectionConfigurationsProperties.cs =================================================================== diff -u --- Riskeer/Piping/src/Riskeer.Piping.Forms/PropertyClasses/PipingFailureMechanismSectionConfigurationsProperties.cs (revision 0) +++ Riskeer/Piping/src/Riskeer.Piping.Forms/PropertyClasses/PipingFailureMechanismSectionConfigurationsProperties.cs (revision 660e8b24bbfd2f862779a8d4d6ab36f698cf2757) @@ -0,0 +1,125 @@ +// Copyright (C) Stichting Deltares and State of the Netherlands 2023. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer 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; +using System.ComponentModel; +using Core.Common.Base; +using Core.Common.Util.Attributes; +using Core.Gui.Attributes; +using Core.Gui.Converters; +using Core.Gui.PropertyBag; +using Riskeer.Common.Data.FailureMechanism; +using Riskeer.Common.Forms.Helpers; +using Riskeer.Common.Forms.PropertyClasses; +using Riskeer.Piping.Data; +using RiskeerCommonFormsResources = Riskeer.Common.Forms.Properties.Resources; + +namespace Riskeer.Piping.Forms.PropertyClasses +{ + /// + /// ViewModel of for the properties panel + /// to show a collection of . + /// + public class PipingFailureMechanismSectionConfigurationsProperties : ObjectProperties, IDisposable + { + private readonly Func getPropertyChangeHandlerFunc; + private readonly Observer failureMechanismObserver; + private readonly RecursiveObserver, FailureMechanismSectionConfiguration> sectionConfigurationsObserver; + + /// + /// Creates a new instance of . + /// + /// The failure mechanism to show the section configurations for. + /// + /// Thrown when any parameter is null. + public PipingFailureMechanismSectionConfigurationsProperties(PipingFailureMechanism failureMechanism, + Func getPropertyChangeHandlerFunc) + { + if (failureMechanism == null) + { + throw new ArgumentNullException(nameof(failureMechanism)); + } + + if (getPropertyChangeHandlerFunc == null) + { + throw new ArgumentNullException(nameof(getPropertyChangeHandlerFunc)); + } + + this.getPropertyChangeHandlerFunc = getPropertyChangeHandlerFunc; + + data = failureMechanism; + + failureMechanismObserver = new Observer(OnRefreshRequired) + { + Observable = data + }; + + sectionConfigurationsObserver = new RecursiveObserver, FailureMechanismSectionConfiguration>( + OnRefreshRequired, + sectionConfiguration => sectionConfiguration) + { + Observable = data.SectionConfigurations + }; + } + + [PropertyOrder(1)] + [ResourcesCategory(typeof(RiskeerCommonFormsResources), nameof(RiskeerCommonFormsResources.Categories_General))] + [ResourcesDisplayName(typeof(RiskeerCommonFormsResources), nameof(RiskeerCommonFormsResources.ObservableCollectionWithSourcePath_SourcePath_DisplayName))] + [ResourcesDescription(typeof(RiskeerCommonFormsResources), nameof(RiskeerCommonFormsResources.FailureMechanismSections_SourcePath_Description))] + public string SourcePath + { + get + { + return data.FailureMechanismSectionSourcePath; + } + } + + [PropertyOrder(2)] + [ResourcesCategory(typeof(RiskeerCommonFormsResources), nameof(RiskeerCommonFormsResources.Categories_General))] + [ResourcesDisplayName(typeof(RiskeerCommonFormsResources), nameof(RiskeerCommonFormsResources.FailureMechanismSections_DisplayName))] + [ResourcesDescription(typeof(RiskeerCommonFormsResources), nameof(RiskeerCommonFormsResources.FailureMechanismSections_Description))] + [TypeConverter(typeof(ExpandableArrayConverter))] + public PipingFailureMechanismSectionConfigurationProperties[] SectionConfigurations + { + get + { + return FailureMechanismSectionPresentationHelper.CreatePresentableFailureMechanismSectionConfigurations( + data.SectionConfigurations, + CreateFailureMechanismSectionConfigurationProperties); + } + } + + public void Dispose() + { + failureMechanismObserver.Dispose(); + sectionConfigurationsObserver.Dispose(); + } + + private PipingFailureMechanismSectionConfigurationProperties CreateFailureMechanismSectionConfigurationProperties( + PipingFailureMechanismSectionConfiguration sectionConfiguration, + double sectionStart, + double sectionEnd) + { + return new PipingFailureMechanismSectionConfigurationProperties(sectionConfiguration, sectionStart, sectionEnd, + data.GeneralInput.B, getPropertyChangeHandlerFunc(sectionConfiguration)); + } + } +} \ No newline at end of file Index: Riskeer/Piping/test/Riskeer.Piping.Forms.Test/PipingFailureMechanismSectionConfigurationsPropertiesTest.cs =================================================================== diff -u --- Riskeer/Piping/test/Riskeer.Piping.Forms.Test/PipingFailureMechanismSectionConfigurationsPropertiesTest.cs (revision 0) +++ Riskeer/Piping/test/Riskeer.Piping.Forms.Test/PipingFailureMechanismSectionConfigurationsPropertiesTest.cs (revision 660e8b24bbfd2f862779a8d4d6ab36f698cf2757) @@ -0,0 +1,212 @@ +// Copyright (C) Stichting Deltares and State of the Netherlands 2023. All rights reserved. +// +// This file is part of Riskeer. +// +// Riskeer 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; +using System.ComponentModel; +using System.Linq; +using Core.Common.Base; +using Core.Common.TestUtil; +using Core.Gui.Converters; +using Core.Gui.PropertyBag; +using Core.Gui.TestUtil; +using NUnit.Framework; +using Rhino.Mocks; +using Riskeer.Common.Data.FailureMechanism; +using Riskeer.Common.Data.TestUtil; +using Riskeer.Common.Forms.PropertyClasses; +using Riskeer.Piping.Data; +using Riskeer.Piping.Forms.PropertyClasses; + +namespace Riskeer.Piping.Forms.Test +{ + [TestFixture] + public class PipingFailureMechanismSectionConfigurationsPropertiesTest + { + [Test] + public void Constructor_FailureMechanismNull_ThrowsArgumentNullException() + { + // Setup + var mocks = new MockRepository(); + var changeHandler = mocks.Stub(); + mocks.ReplayAll(); + + // Call + void Call() => new PipingFailureMechanismSectionConfigurationsProperties(null, configuration => changeHandler); + + // Assert + var exception = Assert.Throws(Call); + Assert.AreEqual("failureMechanism", exception.ParamName); + mocks.VerifyAll(); + } + + [Test] + public void Constructor_GetPropertyChangeHandlerFuncNull_ThrowsArgumentNullException() + { + // Setup + var failureMechanism = new PipingFailureMechanism(); + + // Call + void Call() => new PipingFailureMechanismSectionConfigurationsProperties(failureMechanism, null); + + // Assert + var exception = Assert.Throws(Call); + Assert.AreEqual("getPropertyChangeHandlerFunc", exception.ParamName); + } + + [Test] + public void Constructor_ExpectedValues() + { + // Setup + const string sourcePath = "just//a//section//path"; + + var mocks = new MockRepository(); + var changeHandler = mocks.Stub(); + mocks.ReplayAll(); + + FailureMechanismSection section = FailureMechanismSectionTestFactory.CreateFailureMechanismSection(); + var failureMechanism = new PipingFailureMechanism(); + failureMechanism.SetSections(new[] + { + section + }, sourcePath); + + // Call + using (var properties = new PipingFailureMechanismSectionConfigurationsProperties(failureMechanism, configuration => changeHandler)) + { + // Assert + Assert.IsInstanceOf>(properties); + Assert.IsInstanceOf(properties); + Assert.AreSame(failureMechanism, properties.Data); + + TestHelper.AssertTypeConverter( + nameof(FailureMechanismSectionsProperties.Sections)); + IObservableEnumerable sectionConfigurations = failureMechanism.SectionConfigurations; + Assert.AreEqual(sectionConfigurations.Count(), properties.SectionConfigurations.Length); + + double sectionStart = 0; + for (var i = 0; i < sectionConfigurations.Count(); i++) + { + PipingFailureMechanismSectionConfiguration sectionConfiguration = sectionConfigurations.ElementAt(i); + PipingFailureMechanismSectionConfigurationProperties property = properties.SectionConfigurations[i]; + Assert.AreSame(sectionConfiguration.Section, property.Data); + + double sectionEnd = sectionStart + sectionConfiguration.Section.Length; + Assert.AreEqual(sectionStart, property.SectionStart, property.SectionStart.GetAccuracy()); + Assert.AreEqual(sectionEnd, property.SectionEnd, property.SectionEnd.GetAccuracy()); + sectionStart = sectionEnd; + } + + Assert.AreEqual(sourcePath, properties.SourcePath); + } + } + + [Test] + public void Constructor_Always_PropertiesHaveExpectedAttributesValues() + { + // Setup + var mocks = new MockRepository(); + var changeHandler = mocks.Stub(); + mocks.ReplayAll(); + + var failureMechanism = new PipingFailureMechanism(); + + // Call + using (var properties = new PipingFailureMechanismSectionConfigurationsProperties(failureMechanism, configuration => changeHandler)) + { + // Assert + PropertyDescriptorCollection dynamicProperties = PropertiesTestHelper.GetAllVisiblePropertyDescriptors(properties); + Assert.AreEqual(2, dynamicProperties.Count); + const string generalCategoryName = "Algemeen"; + + PropertyDescriptor sourcePathProperty = dynamicProperties[0]; + PropertiesTestHelper.AssertRequiredPropertyDescriptorProperties(sourcePathProperty, + generalCategoryName, + "Bronlocatie", + "De locatie van het bestand waaruit de vakindeling is geïmporteerd.", + true); + + PropertyDescriptor sectionsProperty = dynamicProperties[1]; + PropertiesTestHelper.AssertRequiredPropertyDescriptorProperties(sectionsProperty, + generalCategoryName, + "Vakindeling", + "Vakindeling waarmee de waterkering voor dit faalmechanisme is " + + "geschematiseerd ten behoeve van de beoordeling.", + true); + mocks.VerifyAll(); + } + } + + [Test] + public void GivenPropertyControlWithData_WhenFailureMechanismUpdated_RefreshRequiredEventRaised() + { + // Given + var mocks = new MockRepository(); + var changeHandler = mocks.Stub(); + mocks.ReplayAll(); + + var failureMechanism = new PipingFailureMechanism(); + + // Call + using (var properties = new PipingFailureMechanismSectionConfigurationsProperties(failureMechanism, configuration => changeHandler)) + { + var refreshRequiredRaised = 0; + properties.RefreshRequired += (sender, args) => refreshRequiredRaised++; + + // When + failureMechanism.NotifyObservers(); + + // Then + Assert.AreEqual(1, refreshRequiredRaised); + } + } + + [Test] + public void GivenPropertyControlWithData_WhenFailureMechanismSectionConfigurationUpdated_RefreshRequiredEventRaised() + { + // Given + var mocks = new MockRepository(); + var changeHandler = mocks.Stub(); + mocks.ReplayAll(); + + FailureMechanismSection section = FailureMechanismSectionTestFactory.CreateFailureMechanismSection(); + var failureMechanism = new PipingFailureMechanism(); + FailureMechanismTestHelper.SetSections(failureMechanism, new[] + { + section + }); + + var sectionConfiguration = failureMechanism.SectionConfigurations.First(); + + // Call + using (var properties = new PipingFailureMechanismSectionConfigurationsProperties(failureMechanism, configuration => changeHandler)) + { + var refreshRequiredRaised = 0; + properties.RefreshRequired += (sender, args) => refreshRequiredRaised++; + + // When + sectionConfiguration.NotifyObservers(); + + // Then + Assert.AreEqual(1, refreshRequiredRaised); + } + } + } +} \ No newline at end of file