Index: Ringtoets/Piping/src/Ringtoets.Piping.Forms/PropertyClasses/PipingCalculationInputsProperties.cs =================================================================== diff -u -r7570b93f301f4503b1c787ecdba215f41eda684a -r92aec43246b1e70b87a37a2c1b464d3ca0226bae --- Ringtoets/Piping/src/Ringtoets.Piping.Forms/PropertyClasses/PipingCalculationInputsProperties.cs (.../PipingCalculationInputsProperties.cs) (revision 7570b93f301f4503b1c787ecdba215f41eda684a) +++ Ringtoets/Piping/src/Ringtoets.Piping.Forms/PropertyClasses/PipingCalculationInputsProperties.cs (.../PipingCalculationInputsProperties.cs) (revision 92aec43246b1e70b87a37a2c1b464d3ca0226bae) @@ -4,9 +4,10 @@ using Core.Common.Gui; using Core.Common.Utils; using Ringtoets.Piping.Data; - +using Ringtoets.Piping.Data.Probabilistics; using Ringtoets.Piping.Forms.PresentationObjects; using Ringtoets.Piping.Forms.Properties; +using Ringtoets.Piping.Forms.TypeConverters; using Ringtoets.Piping.Forms.UITypeEditors; namespace Ringtoets.Piping.Forms.PropertyClasses @@ -110,18 +111,19 @@ } } + [TypeConverter(typeof(NormalDistributionTypeConverter))] [ResourcesCategory(typeof(Resources), "Categories_General")] [ResourcesDisplayName(typeof(Resources), "PipingDataPhreaticLevelExitDisplayName")] [ResourcesDescription(typeof(Resources), "PipingDataPhreaticLevelExitDescription")] - public double PhreaticLevelExit + public NormalDistribution PhreaticLevelExit { get { - return data.PipingData.PhreaticLevelExit.Mean; + return data.PipingData.PhreaticLevelExit; } set { - data.PipingData.PhreaticLevelExit.Mean = value; + data.PipingData.PhreaticLevelExit = value; data.PipingData.NotifyObservers(); } } Index: Ringtoets/Piping/src/Ringtoets.Piping.Forms/Ringtoets.Piping.Forms.csproj =================================================================== diff -u -ra950714ad9510756331d862aa35695fa0b2ed03b -r92aec43246b1e70b87a37a2c1b464d3ca0226bae --- Ringtoets/Piping/src/Ringtoets.Piping.Forms/Ringtoets.Piping.Forms.csproj (.../Ringtoets.Piping.Forms.csproj) (revision a950714ad9510756331d862aa35695fa0b2ed03b) +++ Ringtoets/Piping/src/Ringtoets.Piping.Forms/Ringtoets.Piping.Forms.csproj (.../Ringtoets.Piping.Forms.csproj) (revision 92aec43246b1e70b87a37a2c1b464d3ca0226bae) @@ -74,6 +74,8 @@ + + @@ -104,10 +106,6 @@ Core.Common.Version False - - {D64E4F0E-E341-496F-82B2-941AD202B4E3} - Ringtoets.Piping.Calculation - {10B8D63D-87E8-46DF-ACA9-A8CF22EE8FB5} Ringtoets.Piping.Service @@ -148,6 +146,7 @@ + Index: Ringtoets/Piping/src/Ringtoets.Piping.Forms/TypeConverters/NormalDistributionTypeConverter.cs =================================================================== diff -u --- Ringtoets/Piping/src/Ringtoets.Piping.Forms/TypeConverters/NormalDistributionTypeConverter.cs (revision 0) +++ Ringtoets/Piping/src/Ringtoets.Piping.Forms/TypeConverters/NormalDistributionTypeConverter.cs (revision 92aec43246b1e70b87a37a2c1b464d3ca0226bae) @@ -0,0 +1,97 @@ +using System; +using System.ComponentModel; +using System.Globalization; + +using Core.Common.BaseDelftTools; +using Core.Common.Utils.PropertyBag.Dynamic; +using Core.Common.Utils.Reflection; + +using Ringtoets.Piping.Data.Probabilistics; +using Ringtoets.Piping.Forms.PresentationObjects; +using Ringtoets.Piping.Forms.PropertyClasses; + +namespace Ringtoets.Piping.Forms.TypeConverters +{ + /// + /// A implementation for + /// properties. + /// + /// This class has been designed to be used in . + /// If its reused somewhere else, change notification might not work properly. + public class NormalDistributionTypeConverter : TypeConverter + { + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + if (destinationType == typeof(string)) + { + var distribution = (NormalDistribution)value; + return String.Format("Normale verdeling (\u03BC = {0}, \u03C3 = {1})", + distribution.Mean.ToString(culture), + distribution.StandardDeviation.ToString(culture)); + } + return base.ConvertTo(context, culture, value, destinationType); + } + + public override bool GetPropertiesSupported(ITypeDescriptorContext context) + { + return true; + } + + public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) + { + IObservable observableParent = GetObservableOwnerOfDistribution(context); + + var propertyDescriptorCollection = TypeDescriptor.GetProperties(value); + var properties = new PropertyDescriptor[2]; + properties[0] = CreateMeanPropertyDescriptor(propertyDescriptorCollection, observableParent); + properties[1] = CreateStandardDeviationPropertyDescriptor(propertyDescriptorCollection, observableParent); + + return new PropertyDescriptorCollection(properties); + } + + private static IObservable GetObservableOwnerOfDistribution(ITypeDescriptorContext context) + { + if (context == null) + { + return null; + } + // Sadly, we need this hack in order to update the correct class + var dynamicPropertyBag = context.Instance as DynamicPropertyBag; + if (dynamicPropertyBag == null) + { + return null; + } + + // Note: If this type converter is going to be reused for other classes, we + // might want to reconsider how we want to propagate IObservable updates! + var pipingCalculationInputProperties = dynamicPropertyBag.WrappedObject as PipingCalculationInputsProperties; + return pipingCalculationInputProperties != null ? + ((PipingCalculationInputs)pipingCalculationInputProperties.Data).PipingData : + null; + } + + private PropertyDescriptor CreateMeanPropertyDescriptor(PropertyDescriptorCollection originalProperties, IObservable observableParent) + { + string propertyName = TypeUtils.GetMemberName(nd => nd.Mean); + PropertyDescriptor originalMeanPropertyDescriptor = originalProperties.Find(propertyName, false); + return new TextPropertyDescriptorDecorator(originalMeanPropertyDescriptor, + "\u03BC", + "De gemiddelde waarde van de normale verdeling.") + { + ObservableParent = observableParent + }; + } + + private PropertyDescriptor CreateStandardDeviationPropertyDescriptor(PropertyDescriptorCollection originalProperties, IObservable observableParent) + { + string propertyName = TypeUtils.GetMemberName(nd => nd.StandardDeviation); + PropertyDescriptor originalStandardDeviationPropertyDescriptor = originalProperties.Find(propertyName, false); + return new TextPropertyDescriptorDecorator(originalStandardDeviationPropertyDescriptor, + "\u03C3", + "De standaardafwijking van de normale verdeling.") + { + ObservableParent = observableParent + }; + } + } +} \ No newline at end of file Index: Ringtoets/Piping/src/Ringtoets.Piping.Forms/TypeConverters/TextPropertyDescriptorDecorator.cs =================================================================== diff -u --- Ringtoets/Piping/src/Ringtoets.Piping.Forms/TypeConverters/TextPropertyDescriptorDecorator.cs (revision 0) +++ Ringtoets/Piping/src/Ringtoets.Piping.Forms/TypeConverters/TextPropertyDescriptorDecorator.cs (revision 92aec43246b1e70b87a37a2c1b464d3ca0226bae) @@ -0,0 +1,111 @@ +using System; +using System.ComponentModel; + +using Core.Common.BaseDelftTools; + +namespace Ringtoets.Piping.Forms.TypeConverters +{ + /// + /// This class allows for overriding and + /// of a given . + /// + public class TextPropertyDescriptorDecorator : PropertyDescriptor + { + private readonly string displayNameOverride; + private readonly string descriptionOverride; + private readonly PropertyDescriptor wrappedDescriptor; + + /// + /// Initializes a new instance of the class. + /// + /// The property descriptor being decorated. + /// The custom display name. + /// The custom description. + public TextPropertyDescriptorDecorator(PropertyDescriptor descr, string customDisplayName, string customDescription) + : base(descr) + { + displayNameOverride = customDisplayName; + descriptionOverride = customDescription; + wrappedDescriptor = descr; + } + + public override string DisplayName + { + get + { + return displayNameOverride; + } + } + + public override string Description + { + get + { + return descriptionOverride; + } + } + + /// + /// Gets or sets the observable object whose should notify all observers when + /// is called. + /// + public IObservable ObservableParent { get; set; } + + #region Members delegated to wrapped descriptor + + public override bool CanResetValue(object component) + { + return wrappedDescriptor.CanResetValue(component); + } + + public override object GetValue(object component) + { + return wrappedDescriptor.GetValue(component); + } + + public override void ResetValue(object component) + { + wrappedDescriptor.ResetValue(component); + } + + public override void SetValue(object component, object value) + { + wrappedDescriptor.SetValue(component, value); + if (ObservableParent != null) + { + ObservableParent.NotifyObservers(); + } + } + + public override bool ShouldSerializeValue(object component) + { + return wrappedDescriptor.ShouldSerializeValue(component); + } + + public override Type ComponentType + { + get + { + return wrappedDescriptor.ComponentType; + } + } + + public override bool IsReadOnly + { + get + { + return wrappedDescriptor.IsReadOnly; + } + } + + public override Type PropertyType + { + get + { + return wrappedDescriptor.PropertyType; + } + } + + #endregion + } +} \ No newline at end of file Index: Ringtoets/Piping/test/Ringtoets.Piping.Forms.Test/PropertyClasses/PipingCalculationInputsPropertiesTest.cs =================================================================== diff -u -ra483049c20ef6d26addd0718d0f31ae1922e6f49 -r92aec43246b1e70b87a37a2c1b464d3ca0226bae --- Ringtoets/Piping/test/Ringtoets.Piping.Forms.Test/PropertyClasses/PipingCalculationInputsPropertiesTest.cs (.../PipingCalculationInputsPropertiesTest.cs) (revision a483049c20ef6d26addd0718d0f31ae1922e6f49) +++ Ringtoets/Piping/test/Ringtoets.Piping.Forms.Test/PropertyClasses/PipingCalculationInputsPropertiesTest.cs (.../PipingCalculationInputsPropertiesTest.cs) (revision 92aec43246b1e70b87a37a2c1b464d3ca0226bae) @@ -57,12 +57,15 @@ // Call & Assert Assert.AreEqual(name, properties.Name); + + Assert.AreEqual(pipingData.PhreaticLevelExit.Mean, properties.PhreaticLevelExit.Mean); + Assert.AreEqual(pipingData.PhreaticLevelExit.StandardDeviation, properties.PhreaticLevelExit.StandardDeviation); + Assert.AreEqual(0, properties.CriticalHeaveGradient); Assert.AreEqual(0, properties.UpliftModelFactor); Assert.AreEqual(0, properties.PiezometricHeadExit); Assert.AreEqual(0, properties.PiezometricHeadPolder); Assert.AreEqual(0, properties.ThicknessCoverageLayer); - Assert.AreEqual(0, properties.PhreaticLevelExit); Assert.AreEqual(0, properties.AssessmentLevel); Assert.AreEqual(0, properties.SellmeijerModelFactor); Assert.AreEqual(0, properties.SeepageLength); Index: Ringtoets/Piping/test/Ringtoets.Piping.Forms.Test/Ringtoets.Piping.Forms.Test.csproj =================================================================== diff -u -ra950714ad9510756331d862aa35695fa0b2ed03b -r92aec43246b1e70b87a37a2c1b464d3ca0226bae --- Ringtoets/Piping/test/Ringtoets.Piping.Forms.Test/Ringtoets.Piping.Forms.Test.csproj (.../Ringtoets.Piping.Forms.Test.csproj) (revision a950714ad9510756331d862aa35695fa0b2ed03b) +++ Ringtoets/Piping/test/Ringtoets.Piping.Forms.Test/Ringtoets.Piping.Forms.Test.csproj (.../Ringtoets.Piping.Forms.Test.csproj) (revision 92aec43246b1e70b87a37a2c1b464d3ca0226bae) @@ -64,6 +64,8 @@ + + Index: Ringtoets/Piping/test/Ringtoets.Piping.Forms.Test/TypeConverters/NormalDistributionTypeConverterTest.cs =================================================================== diff -u --- Ringtoets/Piping/test/Ringtoets.Piping.Forms.Test/TypeConverters/NormalDistributionTypeConverterTest.cs (revision 0) +++ Ringtoets/Piping/test/Ringtoets.Piping.Forms.Test/TypeConverters/NormalDistributionTypeConverterTest.cs (revision 92aec43246b1e70b87a37a2c1b464d3ca0226bae) @@ -0,0 +1,162 @@ +using System.ComponentModel; + +using Core.Common.BaseDelftTools; +using Core.Common.Utils.PropertyBag.Dynamic; + +using NUnit.Framework; + +using Rhino.Mocks; + +using Ringtoets.Piping.Data; +using Ringtoets.Piping.Data.Probabilistics; +using Ringtoets.Piping.Forms.PresentationObjects; +using Ringtoets.Piping.Forms.PropertyClasses; +using Ringtoets.Piping.Forms.TypeConverters; + +namespace Ringtoets.Piping.Forms.Test.TypeConverters +{ + [TestFixture] + public class NormalDistributionTypeConverterTest + { + [Test] + public void DefaultConstructor_ExpectedValues() + { + // Call + var converter = new NormalDistributionTypeConverter(); + + // Assert + Assert.IsInstanceOf(converter); + } + + [Test] + public void CanConvertTo_DestinationTypeIsString_ReturnTrue() + { + // Setup + var converter = new NormalDistributionTypeConverter(); + + // Call + var canConvert = converter.CanConvertTo(typeof(string)); + + // Assert + Assert.IsTrue(canConvert); + } + + [Test] + public void ConvertTo_DestinationTypeIsString_ReturnNormalDistributionSpecs() + { + // Setup + var distribution = new NormalDistribution + { + Mean = 1.1, + StandardDeviation = 2.2 + }; + var converter = new NormalDistributionTypeConverter(); + + // Call + var result = converter.ConvertTo(distribution, typeof(string)); + + // Assert + var expectedText = string.Format("Normale verdeling (\u03BC = {0}, \u03C3 = {1})", + distribution.Mean, distribution.StandardDeviation); + Assert.AreEqual(expectedText, result); + } + + [Test] + public void GetPropertiesSupported_Always_ReturnTrue() + { + // Setup + var converter = new NormalDistributionTypeConverter(); + + // Call + var hasSubProperties = converter.GetPropertiesSupported(); + + // Assert + Assert.IsTrue(hasSubProperties); + } + + [Test] + public void GetProperties_Always_ReturnMeanAndStandardDeviation() + { + // Setup + var distribution = new NormalDistribution(); + var converter = new NormalDistributionTypeConverter(); + + // Call + var properties = converter.GetProperties(distribution); + + // Assert + Assert.IsNotNull(properties); + Assert.AreEqual(2, properties.Count); + var meanPropertyDescriptor = properties[0]; + Assert.AreEqual(distribution.GetType(), meanPropertyDescriptor.ComponentType); + Assert.AreEqual(typeof(double), meanPropertyDescriptor.PropertyType); + Assert.IsFalse(meanPropertyDescriptor.IsReadOnly); + Assert.AreEqual("\u03BC", meanPropertyDescriptor.DisplayName); + Assert.AreEqual("De gemiddelde waarde van de normale verdeling.", meanPropertyDescriptor.Description); + + var stdPropertyDescriptor = properties[1]; + Assert.AreEqual(distribution.GetType(), stdPropertyDescriptor.ComponentType); + Assert.AreEqual(typeof(double), stdPropertyDescriptor.PropertyType); + Assert.IsFalse(stdPropertyDescriptor.IsReadOnly); + Assert.AreEqual("\u03C3", stdPropertyDescriptor.DisplayName); + Assert.AreEqual("De standaardafwijking van de normale verdeling.", stdPropertyDescriptor.Description); + } + + [Test] + public void GetProperties_UsedInContextOfPipingCalculationInputsPropertiesWrappedInDynamicPropertyBag_ShouldReturn() + { + // Setup + + // Call + + // Assert + + } + + #region Integration tests + + [Test] + [TestCase(0)] + [TestCase(1)] + public void GivenContextOfPipingCalculationInputsPropertiesWrappedInDynamicPropertyBag_WhenSettingNewValue_ThenPipingDataNotifiedObserversOfChange(int propertyIndexToChange) + { + // Scenario + var pipingData = new PipingData(); + var calculationInputs = new PipingCalculationInputs + { + PipingData = pipingData + }; + var calculationInputsProperties = new PipingCalculationInputsProperties + { + Data = calculationInputs + }; + var dynamicPropertyBag = new DynamicPropertyBag(calculationInputsProperties); + + var mocks = new MockRepository(); + var typeDescriptorContextMock = mocks.StrictMock(); + typeDescriptorContextMock.Expect(tdc => tdc.Instance).Return(dynamicPropertyBag); + + var observer = mocks.StrictMock(); + observer.Expect(o => o.UpdateObserver()); + mocks.ReplayAll(); + + pipingData.Attach(observer); + + var normalDistribution = calculationInputsProperties.PhreaticLevelExit; + + var properties = new NormalDistributionTypeConverter().GetProperties(typeDescriptorContextMock, normalDistribution); + + // Precondition + Assert.IsNotNull(properties); + + // Event + properties[propertyIndexToChange].SetValue(normalDistribution, 2.3); + + // Result + mocks.VerifyAll(); + } + + #endregion + + } +} \ No newline at end of file Index: Ringtoets/Piping/test/Ringtoets.Piping.Forms.Test/TypeConverters/TextPropertyDescriptorDecoratorTest.cs =================================================================== diff -u --- Ringtoets/Piping/test/Ringtoets.Piping.Forms.Test/TypeConverters/TextPropertyDescriptorDecoratorTest.cs (revision 0) +++ Ringtoets/Piping/test/Ringtoets.Piping.Forms.Test/TypeConverters/TextPropertyDescriptorDecoratorTest.cs (revision 92aec43246b1e70b87a37a2c1b464d3ca0226bae) @@ -0,0 +1,196 @@ +using System.ComponentModel; + +using Core.Common.BaseDelftTools; + +using NUnit.Framework; + +using Rhino.Mocks; + +using Ringtoets.Piping.Forms.TypeConverters; + +namespace Ringtoets.Piping.Forms.Test.TypeConverters +{ + [TestFixture] + public class TextPropertyDescriptorDecoratorTest + { + [Test] + public void ParameteredConstructor_ExpectedValues() + { + // Setup + const string displayName = ""; + const string description = ""; + + var target = new ClassWithDoubleProperty(); + var properties = TypeDescriptor.GetProperties(target); + + PropertyDescriptor getSetProperty = properties[0]; + + // Call + var wrappedProperty = new TextPropertyDescriptorDecorator(getSetProperty, displayName, description); + + // Assert + Assert.AreEqual(displayName, wrappedProperty.DisplayName); + Assert.AreEqual(description, wrappedProperty.Description); + + Assert.AreEqual(getSetProperty.ComponentType, wrappedProperty.ComponentType); + Assert.AreEqual(getSetProperty.IsReadOnly, wrappedProperty.IsReadOnly); + Assert.AreEqual(getSetProperty.PropertyType, wrappedProperty.PropertyType); + Assert.AreEqual(getSetProperty.Name, wrappedProperty.Name); + Assert.AreEqual(getSetProperty.Attributes, wrappedProperty.Attributes); + Assert.AreEqual(getSetProperty.Category, wrappedProperty.Category); + Assert.AreEqual(getSetProperty.Converter, wrappedProperty.Converter); + Assert.AreEqual(getSetProperty.DesignTimeOnly, wrappedProperty.DesignTimeOnly); + Assert.AreEqual(getSetProperty.IsBrowsable, wrappedProperty.IsBrowsable); + Assert.AreEqual(getSetProperty.IsLocalizable, wrappedProperty.IsLocalizable); + Assert.AreEqual(getSetProperty.SerializationVisibility, wrappedProperty.SerializationVisibility); + Assert.AreEqual(getSetProperty.SupportsChangeEvents, wrappedProperty.SupportsChangeEvents); + + Assert.IsNull(wrappedProperty.ObservableParent); + } + + [Test] + public void CanResetValue_Always_DelegateToWrappedPropertyDescriptor() + { + // Setup + var component = new ClassWithDoubleProperty(); + var properties = TypeDescriptor.GetProperties(component); + + PropertyDescriptor getSetProperty = properties[0]; + var wrappedProperty = new TextPropertyDescriptorDecorator(getSetProperty, null, null); + + // Call + var result = wrappedProperty.CanResetValue(component); + + // Assert + Assert.AreEqual(getSetProperty.CanResetValue(component), result); + } + + [Test] + public void GetValue_Always_DelegateToWrappedPropertyDescriptor() + { + // Setup + var component = new ClassWithDoubleProperty + { + GetSetProperty = 1.1 + }; + + var properties = TypeDescriptor.GetProperties(component); + PropertyDescriptor getSetProperty = properties[0]; + + var wrappedProperty = new TextPropertyDescriptorDecorator(getSetProperty, null, null); + + // Call + var result = wrappedProperty.GetValue(component); + + // Assert + Assert.AreEqual(getSetProperty.GetValue(component), result); + Assert.AreEqual(component.GetSetProperty, result); + } + + [Test] + public void ResetValue_Always_DelegateToWrappedPropertyDescriptor() + { + // Setup + const double originalPropertyValue = 1.1; + var component = new ClassWithDoubleProperty + { + GetSetProperty = originalPropertyValue + }; + + var properties = TypeDescriptor.GetProperties(component); + PropertyDescriptor getSetProperty = properties[0]; + + getSetProperty.ResetValue(component); + var expectedPropertyValueAfterReset = component.GetSetProperty; + + var wrappedProperty = new TextPropertyDescriptorDecorator(getSetProperty, null, null); + component.GetSetProperty = originalPropertyValue; + + // Call + wrappedProperty.ResetValue(component); + + // Assert + Assert.AreEqual(expectedPropertyValueAfterReset, component.GetSetProperty); + } + + [Test] + public void SetValue_Always_DelegateToWrappedPropertyDescriptor() + { + // Setup + const double originalPropertyValue = 1.1; + const double newValue = 2.2; + var component = new ClassWithDoubleProperty + { + GetSetProperty = originalPropertyValue + }; + + var properties = TypeDescriptor.GetProperties(component); + PropertyDescriptor getSetProperty = properties[0]; + + getSetProperty.SetValue(component, newValue); + var expectedPropertyValueAfterReset = component.GetSetProperty; + + var wrappedProperty = new TextPropertyDescriptorDecorator(getSetProperty, null, null); + component.GetSetProperty = originalPropertyValue; + + // Call + wrappedProperty.SetValue(component, newValue); + + // Assert + Assert.AreEqual(expectedPropertyValueAfterReset, component.GetSetProperty); + } + + [Test] + public void SetValue_ObservableParentProvided_NotifyObservers() + { + // Setup + var mocks = new MockRepository(); + var observable = mocks.StrictMock(); + observable.Expect(o => o.NotifyObservers()); + mocks.ReplayAll(); + + const double originalPropertyValue = 1.1; + const double newValue = 2.2; + var component = new ClassWithDoubleProperty + { + GetSetProperty = originalPropertyValue + }; + + var properties = TypeDescriptor.GetProperties(component); + PropertyDescriptor getSetProperty = properties[0]; + + var wrappedProperty = new TextPropertyDescriptorDecorator(getSetProperty, null, null) + { + ObservableParent = observable + }; + + // Call + wrappedProperty.SetValue(component, newValue); + + // Assert + mocks.VerifyAll(); + } + + [Test] + public void ShouldSerializeValue_Always_DelegateToWrappedPropertyDescriptor() + { + // Setup + var component = new ClassWithDoubleProperty(); + var properties = TypeDescriptor.GetProperties(component); + + PropertyDescriptor getSetProperty = properties[0]; + var wrappedProperty = new TextPropertyDescriptorDecorator(getSetProperty, null, null); + + // Call + var result = wrappedProperty.ShouldSerializeValue(component); + + // Assert + Assert.AreEqual(getSetProperty.ShouldSerializeValue(component), result); + } + + private class ClassWithDoubleProperty + { + public double GetSetProperty { get; set; } + } + } +} \ No newline at end of file