Refactor double editor config to use attribute map

Remove custom editor attribute classes and migrate all double field validation and formatting (range, decimals, number format) to the attribute map system. Refactor PdmUiDoubleValueEditor to read settings from the field's attributes and always display formatted values. Remove redundant defineEditorAttribute overrides. Add tests for pair<bool, double> field validation. Centralize and simplify double field UI configuration for improved maintainability.
This commit is contained in:
Magne Sjaastad
2026-02-16 16:54:22 +01:00
parent 483a4a9b7b
commit dbe08064ce
21 changed files with 185 additions and 202 deletions
@@ -129,6 +129,10 @@ RimGeoMechCase::RimGeoMechCase()
CAF_PDM_InitField( &m_biotCoefficientType, "BiotCoefficientType", defaultBiotCoefficientType, "Biot Coefficient" );
CAF_PDM_InitField( &m_biotFixedCoefficient, "BiotFixedCoefficient", 1.0, "Fixed Coefficient" );
m_biotFixedCoefficient.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() );
m_biotFixedCoefficient.setRange( 0.0, 1.0 );
m_biotFixedCoefficient.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::DECIMALS, 2 );
m_biotFixedCoefficient.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::NUMBER_FORMAT,
static_cast<int>( caf::NumberFormatType::FIXED ) );
CAF_PDM_InitField( &m_biotResultAddress, "BiotResultAddress", QString( "" ), "Value" );
@@ -1130,16 +1134,6 @@ void RimGeoMechCase::defineEditorAttribute( const caf::PdmFieldHandle* field, QS
{
dynamic_cast<caf::PdmUiPushButtonEditorAttribute*>( attribute )->m_buttonText = "Close Selected Properties";
}
if ( field == &m_biotFixedCoefficient )
{
auto uiDoubleValueEditorAttr = dynamic_cast<caf::PdmUiDoubleValueEditorAttribute*>( attribute );
if ( uiDoubleValueEditorAttr )
{
uiDoubleValueEditorAttr->m_decimals = 2;
uiDoubleValueEditorAttr->m_validator = new QDoubleValidator( 0.0, 1.0, 2 );
}
}
}
//--------------------------------------------------------------------------------------------------
@@ -106,6 +106,10 @@ RimGeoMechResultDefinition::RimGeoMechResultDefinition()
CAF_PDM_InitField( &m_normalizeByHydrostaticPressure, "NormalizeByHSP", false, "Normalize by Hydrostatic Pressure" );
CAF_PDM_InitField( &m_normalizationAirGap, "NormalizationAirGap", 0.0, "Air Gap" );
m_normalizationAirGap.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() );
m_normalizationAirGap.setMinValue( 0.0 );
m_normalizationAirGap.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::DECIMALS, 2 );
m_normalizationAirGap.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::NUMBER_FORMAT,
static_cast<int>( caf::NumberFormatType::FIXED ) );
CAF_PDM_InitField( &m_compactionRefLayerUiField,
"CompactionRefLayerUi",
@@ -544,22 +548,6 @@ void RimGeoMechResultDefinition::initAfterRead()
m_timeLapseBaseTimestep.uiCapability()->setUiReadOnly( resultPositionType() == RIG_WELLPATH_DERIVED );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimGeoMechResultDefinition::defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute )
{
if ( field == &m_normalizationAirGap )
{
auto attr = dynamic_cast<caf::PdmUiDoubleValueEditorAttribute*>( attribute );
if ( attr )
{
attr->m_decimals = 2;
attr->m_validator = new QDoubleValidator( 0.0, std::numeric_limits<double>::max(), 2 );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -99,7 +99,6 @@ private:
bool useUndoRedoForFieldChanged() override;
void initAfterRead() override;
void defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override;
// Metadata and option build tools
std::map<std::string, std::vector<std::string>> getResultMetaDataForUIFieldSetting();
@@ -71,9 +71,15 @@ RimGridCrossPlotRegressionCurve::RimGridCrossPlotRegressionCurve()
CAF_PDM_InitFieldNoDefault( &m_minExtrapolationRangeX, "MinExtrapolationRangeX", "Min" );
m_minExtrapolationRangeX.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() );
m_minExtrapolationRangeX.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::DECIMALS, 2 );
m_minExtrapolationRangeX.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::NUMBER_FORMAT,
static_cast<int>( caf::NumberFormatType::FIXED ) );
CAF_PDM_InitFieldNoDefault( &m_maxExtrapolationRangeX, "MaxExtrapolationRangeX", "Max" );
m_maxExtrapolationRangeX.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() );
m_maxExtrapolationRangeX.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::DECIMALS, 2 );
m_maxExtrapolationRangeX.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::NUMBER_FORMAT,
static_cast<int>( caf::NumberFormatType::FIXED ) );
CAF_PDM_InitField( &m_polynomialDegree, "PolynomialDegree", 3, "Degree" );
m_polynomialDegree.setRange( 1, 50 );
@@ -383,11 +389,6 @@ void RimGridCrossPlotRegressionCurve::defineEditorAttribute( const caf::PdmField
myAttr->m_decimals = 3;
}
}
else if ( field == &m_minExtrapolationRangeX || field == &m_maxExtrapolationRangeX )
{
caf::PdmUiDoubleValueEditorAttribute::testAndSetFixedWithTwoDecimals( attribute );
}
else if ( field == &m_expressionText )
{
auto myAttr = dynamic_cast<caf::PdmUiTextEditorAttribute*>( attribute );
@@ -124,6 +124,12 @@ RimDepthTrackPlot::RimDepthTrackPlot()
CAF_PDM_InitScriptableField( &m_maxVisibleDepth, "MaximumDepth", 1000.0, "Max" );
m_minVisibleDepth.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() );
m_maxVisibleDepth.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() );
m_minVisibleDepth.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::DECIMALS, 2 );
m_minVisibleDepth.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::NUMBER_FORMAT,
static_cast<int>( caf::NumberFormatType::FIXED ) );
m_maxVisibleDepth.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::DECIMALS, 2 );
m_maxVisibleDepth.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::NUMBER_FORMAT,
static_cast<int>( caf::NumberFormatType::FIXED ) );
CAF_PDM_InitScriptableFieldNoDefault( &m_depthAxisGridVisibility, "ShowDepthGridLines", "Show Grid Lines" );
CAF_PDM_InitScriptableField( &m_isAutoScaleDepthEnabled, "AutoScaleDepthEnabled", true, "Auto Scale" );
@@ -1217,17 +1223,6 @@ void RimDepthTrackPlot::initAfterRead()
performAutoNameUpdate();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimDepthTrackPlot::defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute )
{
if ( field == &m_minVisibleDepth || field == &m_maxVisibleDepth )
{
caf::PdmUiDoubleValueEditorAttribute::testAndSetFixedWithTwoDecimals( attribute );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -192,10 +192,9 @@ protected:
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override;
void initAfterRead() override;
void defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override;
void onLoadDataAndUpdate() override;
void updatePlots();
void initAfterRead() override;
void onLoadDataAndUpdate() override;
void updatePlots();
caf::PdmFieldHandle* userDescriptionField() override;
void uiOrderingForFonts( const QString& uiConfigName, caf::PdmUiOrdering& uiOrdering );
@@ -112,6 +112,8 @@ RimMudWeightWindowParameters::RimMudWeightWindowParameters()
CAF_PDM_InitField( &m_wellDeviationType, "WellDeviationSourceType", defaultSourceType, "Well Deviation" );
CAF_PDM_InitField( &m_wellDeviationFixed, "WellDeviationFixed", 0.0, "Fixed Well Deviation" );
m_wellDeviationFixed.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() );
m_wellDeviationFixed.setRange( 0.0, 360.0 );
m_wellDeviationFixed.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::DECIMALS, 2 );
CAF_PDM_InitField( &m_wellDeviationAddress, "WellDeviationAddress", QString( "" ), "Value" );
m_wellDeviationAddress.uiCapability()->setUiEditorTypeName( caf::PdmUiTreeSelectionEditor::uiEditorTypeName() );
@@ -119,6 +121,8 @@ RimMudWeightWindowParameters::RimMudWeightWindowParameters()
CAF_PDM_InitField( &m_wellAzimuthType, "WellAzimuthSourceType", defaultSourceType, "Well Azimuth" );
CAF_PDM_InitField( &m_wellAzimuthFixed, "WellAzimuthFixed", 0.0, "Fixed Well Azimuth" );
m_wellAzimuthFixed.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() );
m_wellAzimuthFixed.setRange( 0.0, 360.0 );
m_wellAzimuthFixed.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::DECIMALS, 2 );
CAF_PDM_InitField( &m_wellAzimuthAddress, "WellAzimuthAddress", QString( "" ), "Value" );
m_wellAzimuthAddress.uiCapability()->setUiEditorTypeName( caf::PdmUiTreeSelectionEditor::uiEditorTypeName() );
@@ -514,23 +518,6 @@ void RimMudWeightWindowParameters::defineGroup( caf::PdmUiOrdering&
addressField->uiCapability()->setUiHidden( *typeField != RimMudWeightWindowParameters::SourceType::PER_ELEMENT );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimMudWeightWindowParameters::defineEditorAttribute( const caf::PdmFieldHandle* field,
QString uiConfigName,
caf::PdmUiEditorAttribute* attribute )
{
if ( field == &m_wellDeviationFixed || field == &m_wellAzimuthFixed )
{
auto uiDoubleValueEditorAttr = dynamic_cast<caf::PdmUiDoubleValueEditorAttribute*>( attribute );
if ( uiDoubleValueEditorAttr )
{
uiDoubleValueEditorAttr->m_validator = new QDoubleValidator( 0.0, 360.0, 3 );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -105,7 +105,6 @@ public:
private:
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
void defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override;
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override;
@@ -46,6 +46,8 @@ RimNonNetLayers::RimNonNetLayers()
CAF_PDM_InitScriptableField( &m_cutOff, "Cutoff", 0.0, "Cutoff" );
m_cutOff.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() );
m_cutOff.setRange( 0.0, 1.0 );
m_cutOff.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::DECIMALS, 2 );
CAF_PDM_InitScriptableFieldNoDefault( &m_facies, "Facies", "Facies" );
@@ -86,21 +88,6 @@ QList<caf::PdmOptionItemInfo> RimNonNetLayers::calculateValueOptions( const caf:
return options;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimNonNetLayers::defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute )
{
if ( field == &m_cutOff )
{
auto uiDoubleValueEditorAttr = dynamic_cast<caf::PdmUiDoubleValueEditorAttribute*>( attribute );
if ( uiDoubleValueEditorAttr )
{
uiDoubleValueEditorAttr->m_validator = new QDoubleValidator( 0.0, 1.0, 2 );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -56,7 +56,6 @@ protected:
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override;
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
void defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override;
RimColorLegend* getFaciesColorLegend();
@@ -216,16 +216,25 @@ RimStimPlanModel::RimStimPlanModel()
CAF_PDM_InitScriptableField( &m_formationDip, "FormationDip", 0.0, "Formation Dip" );
m_formationDip.uiCapability()->setUiReadOnly( true );
m_formationDip.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() );
m_formationDip.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::DECIMALS, 2 );
m_formationDip.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::NUMBER_FORMAT,
static_cast<int>( caf::NumberFormatType::FIXED ) );
CAF_PDM_InitScriptableField( &m_autoComputeBarrier, "AutoComputeBarrier", true, "Auto Compute Barrier" );
CAF_PDM_InitScriptableField( &m_hasBarrier, "Barrier", true, "Barrier" );
CAF_PDM_InitScriptableField( &m_distanceToBarrier, "DistanceToBarrier", 0.0, "Distance To Barrier [m]" );
m_distanceToBarrier.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() );
m_distanceToBarrier.uiCapability()->setUiReadOnly( true );
m_distanceToBarrier.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::DECIMALS, 2 );
m_distanceToBarrier.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::NUMBER_FORMAT,
static_cast<int>( caf::NumberFormatType::FIXED ) );
CAF_PDM_InitScriptableField( &m_barrierDip, "BarrierDip", 0.0, "Barrier Dip" );
m_barrierDip.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() );
m_barrierDip.uiCapability()->setUiReadOnly( true );
m_barrierDip.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::DECIMALS, 2 );
m_barrierDip.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::NUMBER_FORMAT,
static_cast<int>( caf::NumberFormatType::FIXED ) );
CAF_PDM_InitScriptableField( &m_wellPenetrationLayer, "WellPenetrationLayer", 2, "Well Penetration Layer" );
CAF_PDM_InitScriptableField( &m_showOnlyBarrierFault, "ShowOnlyBarrierFault", false, "Show Only Barrier Fault" );
@@ -894,11 +903,6 @@ void RimStimPlanModel::defineUiOrdering( QString uiConfigName, caf::PdmUiOrderin
//--------------------------------------------------------------------------------------------------
void RimStimPlanModel::defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute )
{
if ( field == &m_formationDip || field == &m_barrierDip || field == &m_distanceToBarrier )
{
caf::PdmUiDoubleValueEditorAttribute::testAndSetFixedWithTwoDecimals( attribute );
}
if ( field == &m_MD )
{
caf::PdmUiDoubleSliderEditorAttribute* myAttr = dynamic_cast<caf::PdmUiDoubleSliderEditorAttribute*>( attribute );
@@ -111,9 +111,15 @@ RimStimPlanModelTemplate::RimStimPlanModelTemplate()
CAF_PDM_InitScriptableField( &m_verticalStress, "VerticalStress", defaultStress, "Vertical Stress" );
m_verticalStress.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() );
m_verticalStress.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::DECIMALS, 2 );
m_verticalStress.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::NUMBER_FORMAT,
static_cast<int>( caf::NumberFormatType::FIXED ) );
CAF_PDM_InitScriptableField( &m_verticalStressGradient, "VerticalStressGradient", defaultStressGradient, "Vertical Stress Gradient" );
CAF_PDM_InitScriptableField( &m_stressDepth, "StressDepth", defaultStressDepth, "Stress Depth" );
m_stressDepth.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() );
m_stressDepth.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::DECIMALS, 2 );
m_stressDepth.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::NUMBER_FORMAT,
static_cast<int>( caf::NumberFormatType::FIXED ) );
CAF_PDM_InitScriptableField( &m_referenceTemperature, "ReferenceTemperature", 70.0, "Temperature [C]" );
CAF_PDM_InitScriptableField( &m_referenceTemperatureGradient, "ReferenceTemperatureGradient", 0.025, "Temperature Gradient [C/m]" );
@@ -305,11 +311,6 @@ void RimStimPlanModelTemplate::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiT
//--------------------------------------------------------------------------------------------------
void RimStimPlanModelTemplate::defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute )
{
if ( field == &m_stressDepth || field == &m_verticalStress )
{
caf::PdmUiDoubleValueEditorAttribute::testAndSetFixedWithTwoDecimals( attribute );
}
if ( field == &m_faciesInitialPressureConfigs )
{
auto tvAttribute = dynamic_cast<caf::PdmUiTableViewEditorAttribute*>( attribute );
@@ -45,8 +45,14 @@ RimDepthSurface::RimDepthSurface()
CAF_PDM_InitField( &m_depthLowerLimit, "DepthLowerLimit", 0.0, "Lower Limit" );
m_depthLowerLimit.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() );
m_depthLowerLimit.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::DECIMALS, 2 );
m_depthLowerLimit.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::NUMBER_FORMAT,
static_cast<int>( caf::NumberFormatType::FIXED ) );
CAF_PDM_InitField( &m_depthUpperLimit, "DepthUpperLimit", 100000.0, "Upper Limit" );
m_depthUpperLimit.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() );
m_depthUpperLimit.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::DECIMALS, 2 );
m_depthUpperLimit.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::NUMBER_FORMAT,
static_cast<int>( caf::NumberFormatType::FIXED ) );
m_minX.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleSliderEditor::uiEditorTypeName() );
m_maxX.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleSliderEditor::uiEditorTypeName() );
@@ -152,8 +158,6 @@ void RimDepthSurface::defineEditorAttribute( const caf::PdmFieldHandle* field, Q
{
RimSurface::defineEditorAttribute( field, uiConfigName, attribute );
caf::PdmUiDoubleValueEditorAttribute::testAndSetFixedWithTwoDecimals( attribute );
if ( field == &m_depth )
{
if ( auto attr = dynamic_cast<caf::PdmUiDoubleSliderEditorAttribute*>( attribute ) )
@@ -82,6 +82,10 @@ RimWellMeasurementInView::RimWellMeasurementInView()
CAF_PDM_InitField( &m_radiusScaleFactor, "RadiusScaleFactor", 2.5, "Radius Scale" );
m_radiusScaleFactor.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() );
m_radiusScaleFactor.setRange( 0.001, 100.0 );
m_radiusScaleFactor.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::DECIMALS, 2 );
m_radiusScaleFactor.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::NUMBER_FORMAT,
static_cast<int>( caf::NumberFormatType::FIXED ) );
setName( "Well Measurement" );
@@ -146,16 +150,6 @@ void RimWellMeasurementInView::defineEditorAttribute( const caf::PdmFieldHandle*
myAttr->m_maximum = m_maximumResultValue;
}
}
if ( field == &m_radiusScaleFactor )
{
caf::PdmUiDoubleValueEditorAttribute* uiDoubleValueEditorAttr = dynamic_cast<caf::PdmUiDoubleValueEditorAttribute*>( attribute );
if ( uiDoubleValueEditorAttr )
{
uiDoubleValueEditorAttr->m_decimals = 2;
uiDoubleValueEditorAttr->m_validator = new QDoubleValidator( 0.001, 100.0, 2 );
}
}
}
//--------------------------------------------------------------------------------------------------
@@ -72,6 +72,9 @@ RimWellPathGeometryDef::RimWellPathGeometryDef()
CAF_PDM_InitScriptableField( &m_airGap, "AirGap", 0.0, "Air Gap" );
m_airGap.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() );
m_airGap.setMinValue( 0.0 );
m_airGap.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::DECIMALS, 2 );
m_airGap.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::NUMBER_FORMAT, static_cast<int>( caf::NumberFormatType::FIXED ) );
CAF_PDM_InitScriptableField( &m_mdAtFirstTarget, "MdAtFirstTarget", 0.0, "MD at First Target" );
m_mdAtFirstTarget.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() );
@@ -775,16 +778,6 @@ void RimWellPathGeometryDef::defineEditorAttribute( const caf::PdmFieldHandle* f
QString::number( m_referencePointUtmXyd()[2], 'f', 2 );
}
}
if ( field == &m_airGap )
{
auto uiDoubleValueEditorAttr = dynamic_cast<caf::PdmUiDoubleValueEditorAttribute*>( attribute );
if ( uiDoubleValueEditorAttr )
{
uiDoubleValueEditorAttr->m_decimals = 2;
uiDoubleValueEditorAttr->m_validator = new QDoubleValidator( 0.0, std::numeric_limits<double>::max(), 2 );
}
}
}
//--------------------------------------------------------------------------------------------------
@@ -778,6 +778,74 @@ TEST( BaseTest, FieldRangeValidation )
delete obj;
}
//--------------------------------------------------------------------------------------------------
/// Test of pair<bool, double> field range validation
//--------------------------------------------------------------------------------------------------
TEST( BaseTest, PairBoolDoubleRangeValidation )
{
class TestObject : public caf::PdmObjectHandle
{
public:
TestObject() { this->addField( &m_toggleValue, "toggleValue" ); }
caf::PdmDataValueField<std::pair<bool, double>> m_toggleValue;
};
TestObject* obj = new TestObject;
// Test setRange with min only
obj->m_toggleValue.setMinValue( 0.00001 );
obj->m_toggleValue.setValue( std::make_pair( true, 5.0 ) );
EXPECT_TRUE( obj->m_toggleValue.isValid() );
EXPECT_TRUE( obj->m_toggleValue.validate().isEmpty() );
obj->m_toggleValue.setValue( std::make_pair( true, 0.0 ) );
EXPECT_FALSE( obj->m_toggleValue.isValid() );
EXPECT_TRUE( obj->m_toggleValue.validate().contains( "below minimum" ) );
// Bool state should not affect validation
obj->m_toggleValue.setValue( std::make_pair( false, 0.0 ) );
EXPECT_FALSE( obj->m_toggleValue.isValid() );
// Test setRange with both min and max
obj->m_toggleValue.setRange( 1.0, 100.0 );
obj->m_toggleValue.setValue( std::make_pair( true, 50.0 ) );
EXPECT_TRUE( obj->m_toggleValue.isValid() );
obj->m_toggleValue.setValue( std::make_pair( true, 1.0 ) );
EXPECT_TRUE( obj->m_toggleValue.isValid() );
obj->m_toggleValue.setValue( std::make_pair( true, 100.0 ) );
EXPECT_TRUE( obj->m_toggleValue.isValid() );
obj->m_toggleValue.setValue( std::make_pair( true, 0.5 ) );
EXPECT_FALSE( obj->m_toggleValue.isValid() );
EXPECT_TRUE( obj->m_toggleValue.validate().contains( "below minimum" ) );
obj->m_toggleValue.setValue( std::make_pair( true, 200.0 ) );
EXPECT_FALSE( obj->m_toggleValue.isValid() );
EXPECT_TRUE( obj->m_toggleValue.validate().contains( "exceeds maximum" ) );
// Test clearRange
obj->m_toggleValue.clearRange();
obj->m_toggleValue.setValue( std::make_pair( true, -1000.0 ) );
EXPECT_TRUE( obj->m_toggleValue.isValid() );
// Test clampValue
obj->m_toggleValue.setRange( 0.0, 10.0 );
auto clamped = obj->m_toggleValue.clampValue( std::make_pair( true, 15.0 ) );
EXPECT_EQ( 10.0, clamped.second );
EXPECT_TRUE( clamped.first );
clamped = obj->m_toggleValue.clampValue( std::make_pair( false, -5.0 ) );
EXPECT_EQ( 0.0, clamped.second );
EXPECT_FALSE( clamped.first );
delete obj;
}
//--------------------------------------------------------------------------------------------------
/// Test of independent min/max value validation
//--------------------------------------------------------------------------------------------------
@@ -1,5 +1,7 @@
#include "ValidationTest.h"
#include "cafPdmUiDoubleValueEditor.h"
#include <QDebug>
CAF_PDM_SOURCE_INIT( ValidationTestObject, "ValidationTestObject" );
@@ -13,7 +15,7 @@ ValidationTestObject::ValidationTestObject()
// Temperature field: -273.15 to 1000.0 Celsius
CAF_PDM_InitField( &m_temperature, "temperature", 20.0, "Temperature (°C)", "", "", "" );
m_temperature.uiCapability()->setUiToolTip( "Valid range: -273.15 to 1000.0 °C" );
//m_temperature.uiCapability()->setUiToolTip( "Valid range: -273.15 to 1000.0 °C" );
m_temperature.setRange( -273.15, 1000.0 );
// Age field: 0 to 150 years
@@ -23,8 +25,10 @@ ValidationTestObject::ValidationTestObject()
// Percentage field: 0 to 100
CAF_PDM_InitField( &m_percentage, "percentage", 50.0, "Percentage (%)", "", "", "" );
m_percentage.uiCapability()->setUiToolTip( "Valid range: 0 to 100%" );
m_percentage.uiCapability()->setUiToolTip( "Valid range: 0 to 100%, 4 significant digits" );
m_percentage.setRange( 0.0, 100.0 );
m_percentage.uiCapability()->setAttribute( caf::PdmUiDoubleValueEditor::Keys::DECIMALS, 4 );
m_percentage.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() );
// Count field: minimum value only (>= 0) and must be even (custom callback)
CAF_PDM_InitField( &m_count, "count", 0, "Count", "", "", "" );
@@ -61,6 +65,12 @@ ValidationTestObject::ValidationTestObject()
CAF_PDM_InitField( &m_rangeField, "rangeField", 0.0, "Range Field", "", "", "" );
m_rangeField.uiCapability()->setUiToolTip( "Valid range: -100.0 to 100.0" );
m_rangeField.setRange( -100.0, 100.0 );
// Toggle+double field with range validation: 0.001 to 1000.0
CAF_PDM_InitField( &m_toggleDoubleField, "toggleDoubleField", std::make_pair( false, 1.0 ), "Toggle Double", "", "", "" );
m_toggleDoubleField.uiCapability()->setUiToolTip( "Valid range: 0.001 to 1000.0" );
m_toggleDoubleField.setRange( 0.001, 1000.0 );
m_toggleDoubleField.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() );
}
//--------------------------------------------------------------------------------------------------
@@ -32,4 +32,7 @@ public:
// Field with both min and max validation
caf::PdmField<double> m_rangeField;
// Toggle+value field with range validation on the value
caf::PdmField<std::pair<bool, double>> m_toggleDoubleField;
};
@@ -45,7 +45,6 @@
#include "cafPdmUiDefaultObjectEditor.h"
#include "cafPdmUiFieldEditorHandle.h"
#include <QDoubleValidator>
#include <QHBoxLayout>
#include <QLabel>
#include <QLineEdit>
@@ -61,13 +60,6 @@ PdmUiDoubleValueEditor::PdmUiDoubleValueEditor()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
PdmUiDoubleValueEditor::~PdmUiDoubleValueEditor()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -79,46 +71,10 @@ void PdmUiDoubleValueEditor::configureAndUpdateUi( const QString& uiConfigName )
m_lineEdit->setEnabled( !uiField()->isUiReadOnly( uiConfigName ) );
caf::PdmUiObjectHandle* uiObject = uiObj( uiField()->fieldHandle()->ownerObject() );
if ( uiObject )
{
uiObject->editorAttribute( uiField()->fieldHandle(), uiConfigName, &m_attributes );
if ( m_attributes.m_validator )
{
m_lineEdit->setValidator( m_attributes.m_validator );
}
}
// Validate: warn about unsupported attributes
uiField()->validateAttributes( "PdmUiDoubleValueEditor", SUPPORTED_ATTRIBUTES, uiConfigName );
// Override with map-based attributes if present (new system takes precedence)
if ( auto uiItem = uiField() )
{
if ( auto val = uiItem->attribute<int>( Keys::DECIMALS, uiConfigName ) )
{
m_attributes.m_decimals = val.value();
}
if ( auto val = uiItem->attribute<int>( Keys::NUMBER_FORMAT, uiConfigName ) )
{
m_attributes.m_numberFormat = static_cast<NumberFormatType>( val.value() );
}
// Validate: warn about unsupported attributes
uiItem->validateAttributes( "PdmUiDoubleValueEditor", SUPPORTED_ATTRIBUTES, uiConfigName );
}
bool valueOk = false;
double value = uiField()->uiValue().toDouble( &valueOk );
QString textValue;
if ( valueOk )
{
textValue = PdmUiNumberFormat::valueToText( value, m_attributes.m_numberFormat, m_attributes.m_decimals );
}
else
{
textValue = uiField()->uiValue().toString();
}
m_lineEdit->setText( textValue );
m_lineEdit->setText( formattedValue() );
}
//--------------------------------------------------------------------------------------------------
@@ -154,9 +110,46 @@ void PdmUiDoubleValueEditor::slotEditingFinished()
void PdmUiDoubleValueEditor::writeValueToField()
{
QString textValue = m_lineEdit->text();
QVariant v;
v = textValue;
QVariant v = textValue;
this->setValueToField( v );
// This is required if the user entered an invalid value, we want to reset the text to the current value in the field
m_lineEdit->setText( formattedValue() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString PdmUiDoubleValueEditor::formattedValue()
{
if ( !uiField() )
{
return {};
}
auto uiFieldHandle = uiField();
NumberFormatType numberFormat = NumberFormatType::AUTO;
int precision = 6;
if ( auto val = uiFieldHandle->attribute<int>( Keys::DECIMALS ) )
{
precision = val.value();
}
if ( auto val = uiFieldHandle->attribute<int>( Keys::NUMBER_FORMAT ) )
{
numberFormat = static_cast<NumberFormatType>( val.value() );
}
bool valueOk = false;
double value = uiFieldHandle->uiValue().toDouble( &valueOk );
if ( valueOk )
{
return PdmUiNumberFormat::valueToText( value, numberFormat, precision );
}
return uiFieldHandle->uiValue().toString();
}
} // end namespace caf
@@ -39,7 +39,6 @@
#include "cafPdmUiFieldLabelEditorHandle.h"
#include "cafPdmUiNumberFormat.h"
#include <QDoubleValidator>
#include <QGroupBox>
#include <QLabel>
#include <QLineEdit>
@@ -49,38 +48,6 @@
namespace caf
{
//==================================================================================================
///
//==================================================================================================
class PdmUiDoubleValueEditorAttribute : public PdmUiEditorAttribute
{
public:
PdmUiDoubleValueEditorAttribute()
{
m_decimals = 6;
m_numberFormat = NumberFormatType::AUTO;
}
void setFixedWithTwoDecimals()
{
m_decimals = 2;
m_numberFormat = NumberFormatType::FIXED;
}
// Convenience function to set the number format to fixed with two decimals
static void testAndSetFixedWithTwoDecimals( caf::PdmUiEditorAttribute* attr )
{
if ( auto doubleAttr = dynamic_cast<caf::PdmUiDoubleValueEditorAttribute*>( attr ) )
{
doubleAttr->setFixedWithTwoDecimals();
}
}
public:
int m_decimals;
NumberFormatType m_numberFormat;
QPointer<QDoubleValidator> m_validator;
};
//==================================================================================================
///
@@ -92,7 +59,6 @@ class PdmUiDoubleValueEditor : public PdmUiFieldLabelEditorHandle
public:
PdmUiDoubleValueEditor();
~PdmUiDoubleValueEditor() override;
// Attribute key constants for compile-time safety and discoverability
struct Keys
@@ -112,12 +78,11 @@ protected slots:
void slotEditingFinished();
private:
void writeValueToField();
void writeValueToField();
QString formattedValue();
private:
QPointer<QLineEdit> m_lineEdit;
PdmUiDoubleValueEditorAttribute m_attributes;
};
} // end namespace caf
@@ -21,7 +21,7 @@ TEST( PdmUiNumberFormatTest, ValueToText )
{ 3.14159, "3.14", NumberFormatType::FIXED, 2 },
{ 0.0, "0.000", NumberFormatType::FIXED, 3 },
{ -1.5, "-1.5", NumberFormatType::FIXED, 1 },
{ 1.0 / 3.0, "0.33333333", NumberFormatType::FIXED, 8 },
{ 1.0 / 3.0, "0.33333333", NumberFormatType::FIXED, 8 },
{ 3.7, "4", NumberFormatType::FIXED, 0 },
{ -2.3, "-2", NumberFormatType::FIXED, 0 },
{ 1234567.89, "1234567.89", NumberFormatType::FIXED, 2 },