diff --git a/.gitignore b/.gitignore index fe50741bd86..75ff96dc8f8 100644 --- a/.gitignore +++ b/.gitignore @@ -62,6 +62,7 @@ Ankh.NoLoad .vs out build +build-bench CMakeSettings.json enc_temp_folder CMakeUserPresets.json diff --git a/ApplicationLibCode/Application/Tools/RiaOptionItemFactory.h b/ApplicationLibCode/Application/Tools/RiaOptionItemFactory.h index 4fdf552330f..4784340612b 100644 --- a/ApplicationLibCode/Application/Tools/RiaOptionItemFactory.h +++ b/ApplicationLibCode/Application/Tools/RiaOptionItemFactory.h @@ -20,6 +20,7 @@ #include "RifEclipseSummaryAddressDefines.h" +#include "cafPdmOptionItemInfo.h" #include "cafPdmUiItem.h" #include diff --git a/ApplicationLibCode/Application/Tools/RiaQDateTimeTools.cpp b/ApplicationLibCode/Application/Tools/RiaQDateTimeTools.cpp index 897c962cad7..45ff7222319 100644 --- a/ApplicationLibCode/Application/Tools/RiaQDateTimeTools.cpp +++ b/ApplicationLibCode/Application/Tools/RiaQDateTimeTools.cpp @@ -23,6 +23,7 @@ #include #include +#include "cafPdmOptionItemInfo.h" #include "cafPdmUiItem.h" #include diff --git a/ApplicationLibCode/Commands/3dView/RicApplyUserDefinedCameraFeature.cpp b/ApplicationLibCode/Commands/3dView/RicApplyUserDefinedCameraFeature.cpp index 95e5c4fc50e..62d466744b7 100644 --- a/ApplicationLibCode/Commands/3dView/RicApplyUserDefinedCameraFeature.cpp +++ b/ApplicationLibCode/Commands/3dView/RicApplyUserDefinedCameraFeature.cpp @@ -94,7 +94,7 @@ void RicApplyUserDefinedCameraFeature::readCameraFromSettings( cvf::Vec3d& eye, QVariant upVariant = settings.value( RicStoreUserDefinedCameraFeature::upName() ); if ( eyeVariant.isNull() || vrpVariant.isNull() || upVariant.isNull() ) return; - caf::PdmValueFieldSpecialization::setFromVariant( eyeVariant, eye ); - caf::PdmValueFieldSpecialization::setFromVariant( vrpVariant, vrp ); - caf::PdmValueFieldSpecialization::setFromVariant( upVariant, up ); + caf::pdmFromVariant( eyeVariant, eye ); + caf::pdmFromVariant( vrpVariant, vrp ); + caf::pdmFromVariant( upVariant, up ); } diff --git a/ApplicationLibCode/Commands/3dView/RicStoreUserDefinedCameraFeature.cpp b/ApplicationLibCode/Commands/3dView/RicStoreUserDefinedCameraFeature.cpp index 3d3c5eb49d4..df84e68d3f0 100644 --- a/ApplicationLibCode/Commands/3dView/RicStoreUserDefinedCameraFeature.cpp +++ b/ApplicationLibCode/Commands/3dView/RicStoreUserDefinedCameraFeature.cpp @@ -104,13 +104,13 @@ void RicStoreUserDefinedCameraFeature::onActionTriggered( bool isChecked ) camera->toLookAt( &eye, &vrp, &up ); - QVariant eyeVariant = caf::PdmValueFieldSpecialization::convert( eye ); + QVariant eyeVariant = caf::pdmToVariant( eye ); settings.setValue( RicStoreUserDefinedCameraFeature::eyeName(), eyeVariant ); - QVariant vrpVariant = caf::PdmValueFieldSpecialization::convert( vrp ); + QVariant vrpVariant = caf::pdmToVariant( vrp ); settings.setValue( RicStoreUserDefinedCameraFeature::viewReferencePointName(), vrpVariant ); - QVariant upVariant = caf::PdmValueFieldSpecialization::convert( up ); + QVariant upVariant = caf::pdmToVariant( up ); settings.setValue( RicStoreUserDefinedCameraFeature::upName(), upVariant ); RiuMainWindow::instance()->refreshViewActions(); diff --git a/ApplicationLibCode/Commands/AnnotationCommands/RicTextAnnotation3dEditor.cpp b/ApplicationLibCode/Commands/AnnotationCommands/RicTextAnnotation3dEditor.cpp index 6b4c40cbd60..2f89c252620 100644 --- a/ApplicationLibCode/Commands/AnnotationCommands/RicTextAnnotation3dEditor.cpp +++ b/ApplicationLibCode/Commands/AnnotationCommands/RicTextAnnotation3dEditor.cpp @@ -177,7 +177,7 @@ void RicTextAnnotation3dEditor::updatePoint( caf::PdmUiFieldHandle* uiField, con cvf::Vec3d domainPos = dispXf->transformToDomainCoord( newPos ); domainPos.z() = -domainPos.z(); - QVariant originVariant = caf::PdmValueFieldSpecialization::convert( domainPos ); + QVariant originVariant = caf::pdmToVariant( domainPos ); caf::PdmUiCommandSystemProxy::instance()->setUiValueToField( uiField, originVariant ); } diff --git a/ApplicationLibCode/Commands/WellPathCommands/PointTangentManipulator/RicPolylineTarget3dEditor.cpp b/ApplicationLibCode/Commands/WellPathCommands/PointTangentManipulator/RicPolylineTarget3dEditor.cpp index 6bf4a98b484..716372a2b35 100644 --- a/ApplicationLibCode/Commands/WellPathCommands/PointTangentManipulator/RicPolylineTarget3dEditor.cpp +++ b/ApplicationLibCode/Commands/WellPathCommands/PointTangentManipulator/RicPolylineTarget3dEditor.cpp @@ -142,7 +142,7 @@ void RicPolylineTarget3dEditor::slotUpdated( const cvf::Vec3d& origin, const cvf cvf::Vec3d domainOrigin = dispXf->transformToDomainCoord( origin ); domainOrigin.z() = -domainOrigin.z(); - QVariant originVariant = caf::PdmValueFieldSpecialization::convert( domainOrigin ); + QVariant originVariant = caf::pdmToVariant( domainOrigin ); caf::PdmUiCommandSystemProxy::instance()->setUiValueToField( target->targetPointUiCapability(), originVariant ); } diff --git a/ApplicationLibCode/ProjectDataModel/RimDataSourceSteppingTools.h b/ApplicationLibCode/ProjectDataModel/RimDataSourceSteppingTools.h index d5e7d446366..25c917157b3 100644 --- a/ApplicationLibCode/ProjectDataModel/RimDataSourceSteppingTools.h +++ b/ApplicationLibCode/ProjectDataModel/RimDataSourceSteppingTools.h @@ -20,6 +20,7 @@ #include "RifEclipseSummaryAddressDefines.h" +#include "cafPdmOptionItemInfo.h" #include "cafPdmUiItem.h" #include "cafPdmValueField.h" diff --git a/ApplicationLibCode/ProjectDataModel/WellPath/RimWellPathGeometryDef.cpp b/ApplicationLibCode/ProjectDataModel/WellPath/RimWellPathGeometryDef.cpp index a1d0f73f50b..3878a6abe45 100644 --- a/ApplicationLibCode/ProjectDataModel/WellPath/RimWellPathGeometryDef.cpp +++ b/ApplicationLibCode/ProjectDataModel/WellPath/RimWellPathGeometryDef.cpp @@ -520,7 +520,7 @@ void RimWellPathGeometryDef::fieldChangedByUi( const caf::PdmFieldHandle* change linkedDefs.end() ); cvf::Vec3d oldPos; - caf::PdmValueFieldSpecialization::setFromVariant( oldValue, oldPos ); + caf::pdmFromVariant( oldValue, oldPos ); auto delta = m_referencePointUtmXyd() - oldPos; diff --git a/CMakeLists.txt b/CMakeLists.txt index ed90cdb5ef2..f6967efa491 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -989,6 +989,9 @@ option(RESINSIGHT_INCLUDE_APPFWK_TESTS "Enable AppFwk Tests" OFF) mark_as_advanced(FORCE RESINSIGHT_INCLUDE_APPFWK_TESTS) if(RESINSIGHT_INCLUDE_APPFWK_TESTS) + # Compile-time benchmark + add_subdirectory(Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench) + # Unit Tests add_subdirectory(Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests) add_subdirectory( @@ -997,6 +1000,7 @@ if(RESINSIGHT_INCLUDE_APPFWK_TESTS) add_subdirectory(Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXml_UnitTests) add_subdirectory(Fwk/AppFwk/cafPdmScripting/cafPdmScripting_UnitTests) add_subdirectory(Fwk/AppFwk/cafUserInterface/cafUserInterface_UnitTests) + add_subdirectory(Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests) # Executables add_subdirectory(Fwk/AppFwk/cafTests/cafTestApplication) @@ -1010,6 +1014,7 @@ if(RESINSIGHT_INCLUDE_APPFWK_TESTS) cafPdmXml_UnitTests cafPdmScripting_UnitTests cafUserInterface_UnitTests + cafPdmCvf_UnitTests cafTestApplication cafTestCvfApplication ) diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmCoreColor3f.h b/Fwk/AppFwk/cafPdmCvf/cafPdmCoreColor3f.h index 04f74780cfb..df04072f929 100644 --- a/Fwk/AppFwk/cafPdmCvf/cafPdmCoreColor3f.h +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmCoreColor3f.h @@ -39,40 +39,31 @@ #include "cvfBase.h" #include "cvfColor3.h" -#include "cafInternalPdmValueFieldSpecializations.h" +#include "cafPdmFieldTraits.h" #include "cafPdmXmlColor3f.h" #include namespace caf { -//================================================================================================== -/// Partial specialization for PdmValueFieldSpecialization< cvf::Color3f > -//================================================================================================== -template <> -class PdmValueFieldSpecialization +inline QVariant pdmToVariant( const cvf::Color3f& value ) { -public: - static QVariant convert( const cvf::Color3f& value ) - { - QColor col; - col.setRgbF( value.r(), value.g(), value.b() ); - - return col; - } - - static void setFromVariant( const QVariant& variantValue, cvf::Color3f& value ) - { - QColor col = variantValue.value(); + QColor col; + col.setRgbF( value.r(), value.g(), value.b() ); + return col; +} - value.set( col.redF(), col.greenF(), col.blueF() ); - } +inline void pdmFromVariant( const QVariant& v, cvf::Color3f& out ) +{ + QColor col = v.value(); + out.set( col.redF(), col.greenF(), col.blueF() ); +} - static bool isEqual( const QVariant& variantValue, const QVariant& variantValue2 ) - { - return variantValue == variantValue2; - } +template <> +struct PdmVariantEqualImpl +{ + static bool equal( const QVariant& a, const QVariant& b ) { return a.value() == b.value(); } }; } // end namespace caf diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmCoreMat4d.h b/Fwk/AppFwk/cafPdmCvf/cafPdmCoreMat4d.h index 44188bb1873..c75109586da 100644 --- a/Fwk/AppFwk/cafPdmCvf/cafPdmCoreMat4d.h +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmCoreMat4d.h @@ -39,7 +39,7 @@ #include "cvfBase.h" #include "cvfMatrix4.h" -#include "cafInternalPdmValueFieldSpecializations.h" +#include "cafPdmFieldTraits.h" #include "cafPdmXmlMat4d.h" @@ -47,35 +47,26 @@ namespace caf { -template <> -class PdmValueFieldSpecialization -{ -public: - /// Convert the field value into a QVariant - static QVariant convert( const cvf::Mat4d& value ) - { - QString str; - - QTextStream textStream( &str ); - textStream << value; - - return QVariant( str ); - } - - /// Set the field value from a QVariant - static void setFromVariant( const QVariant& variantValue, cvf::Mat4d& value ) - { - QString str = variantValue.toString(); - QTextStream textStream( &str ); +inline QVariant pdmToVariant( const cvf::Mat4d& value ) +{ + QString str; + QTextStream textStream( &str ); + textStream << value; + return QVariant( str ); +} - textStream >> value; - } +inline void pdmFromVariant( const QVariant& v, cvf::Mat4d& out ) +{ + QString str = v.toString(); + QTextStream textStream( &str ); + textStream >> out; +} - static bool isEqual( const QVariant& variantValue, const QVariant& variantValue2 ) - { - return variantValue == variantValue2; - } +template <> +struct PdmVariantEqualImpl +{ + static bool equal( const QVariant& a, const QVariant& b ) { return a.toString() == b.toString(); } }; } // end namespace caf diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmCoreVec3d.h b/Fwk/AppFwk/cafPdmCvf/cafPdmCoreVec3d.h index b52e2758580..082adc45b95 100644 --- a/Fwk/AppFwk/cafPdmCvf/cafPdmCoreVec3d.h +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmCoreVec3d.h @@ -39,7 +39,7 @@ #include "cvfBase.h" #include "cvfVector3.h" -#include "cafInternalPdmValueFieldSpecializations.h" +#include "cafPdmFieldTraits.h" #include "cafPdmXmlVec3d.h" @@ -49,35 +49,26 @@ Q_DECLARE_METATYPE( cvf::Vec3d ); namespace caf { -template <> -class PdmValueFieldSpecialization -{ -public: - /// Convert the field value into a QVariant - static QVariant convert( const cvf::Vec3d& value ) - { - QString str; - - QTextStream textStream( &str ); - textStream << value; - - return QVariant( str ); - } - - /// Set the field value from a QVariant - static void setFromVariant( const QVariant& variantValue, cvf::Vec3d& value ) - { - QString str = variantValue.toString(); - QTextStream textStream( &str ); +inline QVariant pdmToVariant( const cvf::Vec3d& value ) +{ + QString str; + QTextStream textStream( &str ); + textStream << value; + return QVariant( str ); +} - textStream >> value; - } +inline void pdmFromVariant( const QVariant& v, cvf::Vec3d& out ) +{ + QString str = v.toString(); + QTextStream textStream( &str ); + textStream >> out; +} - static bool isEqual( const QVariant& variantValue, const QVariant& variantValue2 ) - { - return variantValue == variantValue2; - } +template <> +struct PdmVariantEqualImpl +{ + static bool equal( const QVariant& a, const QVariant& b ) { return a.toString() == b.toString(); } }; } // end namespace caf diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/cafPdmCoreColor3fTest.cpp b/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/cafPdmCoreColor3fTest.cpp index 5dcea1b525a..bf3d7cb6ed1 100644 --- a/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/cafPdmCoreColor3fTest.cpp +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/cafPdmCoreColor3fTest.cpp @@ -33,16 +33,30 @@ TEST( VariantTest, PdmCoreColor3f ) float b = 0.18f; cvf::Color3f myColor( r, g, b ); - QVariant myVariant = caf::PdmValueFieldSpecialization::convert( myColor ); + QVariant myVariant = caf::pdmToVariant( myColor ); cvf::Color3f decoded; - caf::PdmValueFieldSpecialization::setFromVariant( myVariant, decoded ); + caf::pdmFromVariant( myVariant, decoded ); EXPECT_FLOAT_EQ( myColor.r(), decoded.r() ); EXPECT_FLOAT_EQ( myColor.g(), decoded.g() ); EXPECT_NEAR( myColor.b(), decoded.b(), 0.01 ); // For some reason, 0.18 is not close enough to use EXPECT_FLOAT_EQ } +TEST( VariantEqualTest, PdmCoreColor3f ) +{ + cvf::Color3f a( 0.4f, 0.2f, 0.18f ); + cvf::Color3f b( 0.4f, 0.2f, 0.18f ); + cvf::Color3f c( 0.4f, 0.2f, 0.5f ); + + QVariant va = caf::pdmToVariant( a ); + QVariant vb = caf::pdmToVariant( b ); + QVariant vc = caf::pdmToVariant( c ); + + EXPECT_TRUE( caf::pdmVariantEqual( va, vb ) ); + EXPECT_FALSE( caf::pdmVariantEqual( va, vc ) ); +} + TEST( SerializeSeveralTest, PdmCoreColor3f ) { float r = 0.4f; diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/cafPdmCoreMat4dTest.cpp b/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/cafPdmCoreMat4dTest.cpp index 7618bb8d19b..8c17fbcb8c0 100644 --- a/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/cafPdmCoreMat4dTest.cpp +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/cafPdmCoreMat4dTest.cpp @@ -53,10 +53,10 @@ TEST( VariantTest, PdmCoreMat4d ) { cvf::Mat4d myMatrix = createMatrix(); - QVariant myVariant = caf::PdmValueFieldSpecialization::convert( myMatrix ); + QVariant myVariant = caf::pdmToVariant( myMatrix ); cvf::Mat4d decoded; - caf::PdmValueFieldSpecialization::setFromVariant( myVariant, decoded ); + caf::pdmFromVariant( myVariant, decoded ); EXPECT_TRUE( decoded.equals( myMatrix ) ); } diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/cafPdmCoreVec3dTest.cpp b/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/cafPdmCoreVec3dTest.cpp index 7cd3b243544..545c9a70721 100644 --- a/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/cafPdmCoreVec3dTest.cpp +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/cafPdmCoreVec3dTest.cpp @@ -37,14 +37,28 @@ TEST( VariantTest, PdmCoreVec3d ) cvf::Vec3d myVector( a, b, c ); - QVariant myVariant = caf::PdmValueFieldSpecialization::convert( myVector ); + QVariant myVariant = caf::pdmToVariant( myVector ); cvf::Vec3d decoded; - caf::PdmValueFieldSpecialization::setFromVariant( myVariant, decoded ); + caf::pdmFromVariant( myVariant, decoded ); EXPECT_TRUE( decoded.equals( myVector ) ); } +TEST( VariantEqualTest, PdmCoreVec3d ) +{ + cvf::Vec3d a( 1.0, 2.0, 3.0 ); + cvf::Vec3d b( 1.0, 2.0, 3.0 ); + cvf::Vec3d c( 1.0, 2.0, 4.0 ); + + QVariant va = caf::pdmToVariant( a ); + QVariant vb = caf::pdmToVariant( b ); + QVariant vc = caf::pdmToVariant( c ); + + EXPECT_TRUE( caf::pdmVariantEqual( va, vb ) ); + EXPECT_FALSE( caf::pdmVariantEqual( va, vc ) ); +} + TEST( SerializeSeveralTest, PdmCoreVec3d ) { double a = 2.4; diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmMat3d/cafPdmCoreMat3d.h b/Fwk/AppFwk/cafPdmCvf/cafPdmMat3d/cafPdmCoreMat3d.h index 6c8693c146b..15ae8ba7fa5 100644 --- a/Fwk/AppFwk/cafPdmCvf/cafPdmMat3d/cafPdmCoreMat3d.h +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmMat3d/cafPdmCoreMat3d.h @@ -39,41 +39,34 @@ #include "cvfBase.h" #include "cvfMatrix3.h" -#include "cafInternalPdmValueFieldSpecializations.h" +#include "cafPdmFieldTraits.h" #include "cafPdmXmlMat3d.h" +#include + namespace caf { -template <> -class PdmValueFieldSpecialization -{ -public: - /// Convert the field value into a QVariant - static QVariant convert( const cvf::Mat3d& value ) - { - QString str; - - QTextStream textStream( &str ); - textStream << value; - - return QVariant( str ); - } - /// Set the field value from a QVariant - static void setFromVariant( const QVariant& variantValue, cvf::Mat3d& value ) - { - QString str = variantValue.toString(); - - QTextStream textStream( &str ); +inline QVariant pdmToVariant( const cvf::Mat3d& value ) +{ + QString str; + QTextStream textStream( &str ); + textStream << value; + return QVariant( str ); +} - textStream >> value; - } +inline void pdmFromVariant( const QVariant& v, cvf::Mat3d& out ) +{ + QString str = v.toString(); + QTextStream textStream( &str ); + textStream >> out; +} - static bool isEqual( const QVariant& variantValue, const QVariant& variantValue2 ) - { - return variantValue == variantValue2; - } +template <> +struct PdmVariantEqualImpl +{ + static bool equal( const QVariant& a, const QVariant& b ) { return a.toString() == b.toString(); } }; } // end namespace caf diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/CMakeLists.txt b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/CMakeLists.txt index 1e01e6731bf..72a2ec54e41 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/CMakeLists.txt +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/CMakeLists.txt @@ -46,7 +46,7 @@ set(PROJECT_FILES cafPdmReferenceHelper.h cafPdmUiFieldHandleInterface.h cafPdmValueField.h - cafInternalPdmValueFieldSpecializations.h + cafPdmFieldTraits.h cafNotificationCenter.cpp cafNotificationCenter.h cafSignal.h diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafAppEnum.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafAppEnum.h index 047053c4ab5..f47ebb4b7a8 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafAppEnum.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafAppEnum.h @@ -400,3 +400,28 @@ template std::map> AppEnum::m_enumSubset; } // namespace caf + +#include "cafPdmFieldTraits.h" + +namespace caf +{ + +template +QVariant pdmToVariant( const AppEnum& value ) +{ + return QVariant( static_cast( static_cast( value ) ) ); +} + +template +void pdmFromVariant( const QVariant& v, AppEnum& out ) +{ + out = static_cast( v.toInt() ); +} + +template +struct PdmVariantEqualImpl> +{ + static bool equal( const QVariant& a, const QVariant& b ) { return a.toInt() == b.toInt(); } +}; + +} // namespace caf diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafFilePath.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafFilePath.h index 95e4b687505..f46540f06e7 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafFilePath.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafFilePath.h @@ -34,3 +34,26 @@ QTextStream& operator>>( QTextStream& str, caf::FilePath& filePath ); QTextStream& operator<<( QTextStream& str, const caf::FilePath& filePath ); Q_DECLARE_METATYPE( caf::FilePath ); + +#include "cafPdmFieldTraits.h" + +namespace caf +{ + +inline QVariant pdmToVariant( const FilePath& value ) +{ + return QVariant( value.path() ); +} + +inline void pdmFromVariant( const QVariant& v, FilePath& out ) +{ + out.setPath( v.toString() ); +} + +template <> +struct PdmVariantEqualImpl +{ + static bool equal( const QVariant& a, const QVariant& b ) { return a.toString() == b.toString(); } +}; + +} // namespace caf diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafInternalPdmValueFieldSpecializations.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafInternalPdmValueFieldSpecializations.h deleted file mode 100644 index 31cd0b230d4..00000000000 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafInternalPdmValueFieldSpecializations.h +++ /dev/null @@ -1,239 +0,0 @@ -#pragma once - -#include "cafAppEnum.h" -#include "cafFilePath.h" -#include "cafPdmPointer.h" - -#include -#include -#include - -#include - -namespace caf -{ -//================================================================================================== -/// Base class providing default implementations for PdmValueFieldSpecialization methods. -//================================================================================================== -struct PdmValueFieldSpecializationDefaults -{ - static bool isEqual( const QVariant& variantValue, const QVariant& variantValue2 ) - { - return variantValue == variantValue2; - } -}; - -//================================================================================================== -/// Helper base class providing standard QVariant conversion for simple types. -/// Useful for types that only need custom isEqual (like float/double with epsilon comparison). -//================================================================================================== -template -struct PdmValueFieldSpecializationStdConversion -{ - static QVariant convert( const T& value ) { return QVariant::fromValue( value ); } - static void setFromVariant( const QVariant& variantValue, T& value ) { value = variantValue.value(); } -}; - -//================================================================================================== -/// A proxy class that implements the generic QVariant interface for a field -/// -/// This class collects methods that need specialization when introducing a new type in a PdmField. -/// Having those methods in a separate class makes it possible to "partially specialize" the methods -/// for container classes etc. since partial specialization of template functions is not C++ as of yet. -/// -/// When introducing a new type in a PdmField, you might need to implement a (partial)specialization -/// of this class. -//================================================================================================== - -template -class PdmValueFieldSpecialization -{ -public: - /// Convert the field value into a QVariant - static QVariant convert( const T& value ) { return QVariant::fromValue( value ); } - - /// Set the field value from a QVariant - static void setFromVariant( const QVariant& variantValue, T& value ) { value = variantValue.value(); } - - /// Check equality between QVariants that carries a Field Value. - /// The == operator will normally work, but does not support custom types in the QVariant - /// See http://qt-project.org/doc/qt-4.8/qvariant.html#operator-eq-eq-64 - /// Using the == between the real types is more safe. - static bool isEqual( const QVariant& variantValue, const QVariant& variantValue2 ) - { - return variantValue.value() == variantValue2.value(); - } -}; - -//================================================================================================== -/// Partial specialization for caf::AppEnum -//================================================================================================== -template -class PdmValueFieldSpecialization> : public PdmValueFieldSpecializationDefaults -{ -public: - static QVariant convert( const caf::AppEnum& value ) - { - T enumValue = value; - // Explicit cast to an int before storage in a QVariant. This allows the use of enum class instead of enum - return QVariant( static_cast( enumValue ) ); - } - - static void setFromVariant( const QVariant& variantValue, caf::AppEnum& value ) - { - value = static_cast( variantValue.toInt() ); - } -}; - -//================================================================================================== -/// Partial specialization for caf::PdmPointer -/// Used internally to avoid havning to declare everything Q_DECLARE_METATYPE() -/// User must use PdmPtrField or PdmChildField -//================================================================================================== -template -class PdmValueFieldSpecialization> -{ -public: - static QVariant convert( const PdmPointer& value ) - { - return QVariant::fromValue( PdmPointer( value.rawPtr() ) ); - } - - static void setFromVariant( const QVariant& variantValue, caf::PdmPointer& value ) - { - value.setRawPtr( variantValue.value>().rawPtr() ); - } - - static bool isEqual( const QVariant& variantValue, const QVariant& variantValue2 ) - { - return variantValue.value>() == variantValue2.value>(); - } -}; - -//================================================================================================== -/// Partial specialization for std::vector -//================================================================================================== -template -class PdmValueFieldSpecialization> : public PdmValueFieldSpecializationDefaults -{ -public: - static QVariant convert( const std::vector& value ) - { - QList returnList; - typename std::vector::const_iterator it; - for ( it = value.begin(); it != value.end(); ++it ) - { - returnList.push_back( PdmValueFieldSpecialization::convert( *it ) ); - } - - return returnList; - } - - static void setFromVariant( const QVariant& variantValue, std::vector& value ) - { - if ( variantValue.canConvert>() ) - { - value.clear(); - QList lst = variantValue.toList(); - for ( int i = 0; i < lst.size(); ++i ) - { - T val; - PdmValueFieldSpecialization::setFromVariant( lst[i], val ); - - value.push_back( val ); - } - } - } -}; - -//================================================================================================== -/// Partial specialization for std::pair -//================================================================================================== -template -class PdmValueFieldSpecialization> : public PdmValueFieldSpecializationDefaults -{ -public: - static QVariant convert( const std::pair& value ) - { - QList returnList; - - returnList.push_back( PdmValueFieldSpecialization::convert( value.first ) ); - returnList.push_back( PdmValueFieldSpecialization::convert( value.second ) ); - - return returnList; - } - - static void setFromVariant( const QVariant& variantValue, std::pair& value ) - { - if ( variantValue.canConvert>() ) - { - QList lst = variantValue.toList(); - if ( lst.size() == 2 ) - { - T first; - PdmValueFieldSpecialization::setFromVariant( lst[0], first ); - - U second; - PdmValueFieldSpecialization::setFromVariant( lst[1], second ); - - value = std::make_pair( first, second ); - } - } - } -}; - -//================================================================================================== -/// Partial specialization for caf::FilePath -//================================================================================================== -template <> -class PdmValueFieldSpecialization -{ -public: - static QVariant convert( const FilePath& value ) { return QVariant( value.path() ); } - - static void setFromVariant( const QVariant& variantValue, FilePath& value ) - { - value.setPath( variantValue.toString() ); - } - - static bool isEqual( const QVariant& variantValue, const QVariant& variantValue2 ) - { - return variantValue.toString() == variantValue2.toString(); - } -}; - -//================================================================================================== -/// Partial specialization for float -//================================================================================================== -template <> -class PdmValueFieldSpecialization : public PdmValueFieldSpecializationStdConversion -{ -public: - static bool isEqual( const QVariant& variantValue, const QVariant& variantValue2 ) - { - // See PdmFieldWriter::writeFieldData for the precision used when writing float values - // This function is used when comparing values for field editors in PdmFieldUiCap::valueOptions() - - const float epsilon = 1e-6f; - return qAbs( variantValue.value() - variantValue2.value() ) < epsilon; - } -}; - -//================================================================================================== -/// Partial specialization for double -//================================================================================================== -template <> -class PdmValueFieldSpecialization : public PdmValueFieldSpecializationStdConversion -{ -public: - static bool isEqual( const QVariant& variantValue, const QVariant& variantValue2 ) - { - // See PdmFieldWriter::writeFieldData for the precision used when writing double values - // This function is used when comparing values for field editors in PdmFieldUiCap::valueOptions() - - const double epsilon = 1e-8; - return qAbs( variantValue.value() - variantValue2.value() ) < epsilon; - } -}; - -} // End of namespace caf diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/CMakeLists.txt b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/CMakeLists.txt index 927595c7274..5f53c258435 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/CMakeLists.txt +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/CMakeLists.txt @@ -23,6 +23,7 @@ set(PROJECT_FILES cafPdmCore_UnitTests.cpp gtest/gtest-all.cpp cafPdmCoreBasicTest.cpp + cafPdmFieldTraitsTest.cpp cafPdmReferenceHelperTest.cpp cafPdmChildArrayFieldHandleTest.cpp cafSignalTest.cpp diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/cafPdmCoreBasicTest.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/cafPdmCoreBasicTest.cpp index 7a19bd55704..8a27dcd445d 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/cafPdmCoreBasicTest.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/cafPdmCoreBasicTest.cpp @@ -3,6 +3,7 @@ #include "Parent.h" +#include "cafFilePath.h" #include "cafPdmChildArrayField.h" #include "cafPdmChildField.h" #include "cafPdmDataValueField.h" diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/cafPdmFieldTraitsTest.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/cafPdmFieldTraitsTest.cpp new file mode 100644 index 00000000000..8303b76a95f --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/cafPdmFieldTraitsTest.cpp @@ -0,0 +1,490 @@ + +#include "gtest/gtest.h" + +#include "cafAppEnum.h" +#include "cafFilePath.h" +#include "cafPdmFieldTraits.h" +#include "cafPdmObjectHandle.h" +#include "cafPdmPointer.h" + +#include + +#include + +//================================================================================================== +// Test enum for AppEnum tests +//================================================================================================== + +enum class TraitTestEnum +{ + ALPHA, + BETA, + GAMMA +}; + +namespace caf +{ +template <> +void AppEnum::setUp() +{ + addItem( TraitTestEnum::ALPHA, "ALPHA", "Alpha" ); + addItem( TraitTestEnum::BETA, "BETA", "Beta" ); + addItem( TraitTestEnum::GAMMA, "GAMMA", "Gamma" ); + setDefault( TraitTestEnum::ALPHA ); +} +} // namespace caf + +//================================================================================================== +// Minimal PdmObjectHandle subclass for PdmPointer tests +//================================================================================================== + +class TraitTestObject : public caf::PdmObjectHandle +{ +}; + +//================================================================================================== +// pdmToVariant / pdmFromVariant round-trip tests +//================================================================================================== + +TEST( PdmFieldTraits, RoundTrip_Int ) +{ + int original = 42; + QVariant v = caf::pdmToVariant( original ); + int out = 0; + caf::pdmFromVariant( v, out ); + EXPECT_EQ( original, out ); +} + +TEST( PdmFieldTraits, RoundTrip_Double ) +{ + double original = 3.14159265358979; + QVariant v = caf::pdmToVariant( original ); + double out = 0.0; + caf::pdmFromVariant( v, out ); + EXPECT_DOUBLE_EQ( original, out ); +} + +TEST( PdmFieldTraits, RoundTrip_Float ) +{ + float original = 2.71828f; + QVariant v = caf::pdmToVariant( original ); + float out = 0.0f; + caf::pdmFromVariant( v, out ); + EXPECT_FLOAT_EQ( original, out ); +} + +TEST( PdmFieldTraits, RoundTrip_Bool ) +{ + QVariant vTrue = caf::pdmToVariant( true ); + bool out = false; + caf::pdmFromVariant( vTrue, out ); + EXPECT_TRUE( out ); + + QVariant vFalse = caf::pdmToVariant( false ); + caf::pdmFromVariant( vFalse, out ); + EXPECT_FALSE( out ); +} + +TEST( PdmFieldTraits, RoundTrip_QString ) +{ + QString original = "Hello PDM"; + QVariant v = caf::pdmToVariant( original ); + QString out; + caf::pdmFromVariant( v, out ); + EXPECT_EQ( original, out ); +} + +TEST( PdmFieldTraits, RoundTrip_FilePath ) +{ + caf::FilePath original( "/some/path/to/file.txt" ); + QVariant v = caf::pdmToVariant( original ); + + // Must be stored as a string (not as FilePath metatype) + EXPECT_EQ( v.toString(), QString( "/some/path/to/file.txt" ) ); + + caf::FilePath out; + caf::pdmFromVariant( v, out ); + EXPECT_EQ( original.path(), out.path() ); +} + +TEST( PdmFieldTraits, RoundTrip_AppEnum ) +{ + caf::AppEnum original = TraitTestEnum::BETA; + QVariant v = caf::pdmToVariant( original ); + + // Must be stored as int + EXPECT_EQ( v.toInt(), static_cast( TraitTestEnum::BETA ) ); + + caf::AppEnum out; + caf::pdmFromVariant( v, out ); + EXPECT_EQ( static_cast( out ), TraitTestEnum::BETA ); +} + +TEST( PdmFieldTraits, RoundTrip_Vector_Int ) +{ + std::vector original = { 1, 2, 3, 4, 5 }; + QVariant v = caf::pdmToVariant( original ); + + EXPECT_TRUE( v.canConvert>() ); + EXPECT_EQ( v.toList().size(), 5 ); + + std::vector out; + caf::pdmFromVariant( v, out ); + EXPECT_EQ( original, out ); +} + +TEST( PdmFieldTraits, RoundTrip_Vector_Double ) +{ + std::vector original = { 1.1, 2.2, 3.3 }; + QVariant v = caf::pdmToVariant( original ); + std::vector out; + caf::pdmFromVariant( v, out ); + ASSERT_EQ( original.size(), out.size() ); + for ( size_t i = 0; i < original.size(); ++i ) + { + EXPECT_DOUBLE_EQ( original[i], out[i] ); + } +} + +TEST( PdmFieldTraits, RoundTrip_Vector_Empty ) +{ + std::vector original; + QVariant v = caf::pdmToVariant( original ); + + std::vector out = { 99 }; // pre-fill to confirm it gets cleared + caf::pdmFromVariant( v, out ); + EXPECT_TRUE( out.empty() ); +} + +TEST( PdmFieldTraits, RoundTrip_Pair_BoolString ) +{ + auto original = std::make_pair( true, QString( "test" ) ); + QVariant v = caf::pdmToVariant( original ); + + ASSERT_TRUE( v.canConvert>() ); + ASSERT_EQ( v.toList().size(), 2 ); + + std::pair out; + caf::pdmFromVariant( v, out ); + EXPECT_EQ( original.first, out.first ); + EXPECT_EQ( original.second, out.second ); +} + +TEST( PdmFieldTraits, RoundTrip_Pair_BoolDouble ) +{ + auto original = std::make_pair( false, 3.14 ); + QVariant v = caf::pdmToVariant( original ); + + std::pair out; + caf::pdmFromVariant( v, out ); + EXPECT_EQ( original.first, out.first ); + EXPECT_DOUBLE_EQ( original.second, out.second ); +} + +TEST( PdmFieldTraits, RoundTrip_PdmPointer_Null ) +{ + caf::PdmPointer original; + EXPECT_TRUE( original.isNull() ); + + QVariant v = caf::pdmToVariant( original ); + + caf::PdmPointer out; + caf::pdmFromVariant( v, out ); + EXPECT_TRUE( out.isNull() ); +} + +TEST( PdmFieldTraits, RoundTrip_PdmPointer_NonNull ) +{ + auto obj = std::make_unique(); + caf::PdmPointer original( obj.get() ); + + QVariant v = caf::pdmToVariant( original ); + + caf::PdmPointer out; + caf::pdmFromVariant( v, out ); + EXPECT_EQ( original.rawPtr(), out.rawPtr() ); +} + +//================================================================================================== +// pdmVariantEqual tests +//================================================================================================== + +TEST( PdmFieldTraits, VariantEqual_Int ) +{ + QVariant a = caf::pdmToVariant( 42 ); + QVariant b = caf::pdmToVariant( 42 ); + QVariant c = caf::pdmToVariant( 43 ); + + EXPECT_TRUE( caf::pdmVariantEqual( a, b ) ); + EXPECT_FALSE( caf::pdmVariantEqual( a, c ) ); +} + +TEST( PdmFieldTraits, VariantEqual_Double_Exact ) +{ + QVariant a = caf::pdmToVariant( 1.0 ); + QVariant b = caf::pdmToVariant( 1.0 ); + EXPECT_TRUE( caf::pdmVariantEqual( a, b ) ); +} + +TEST( PdmFieldTraits, VariantEqual_Double_WithinEpsilon ) +{ + double base = 1.0; + double epsilon = 1e-8; + QVariant a = caf::pdmToVariant( base ); + QVariant b = caf::pdmToVariant( base + epsilon * 0.5 ); // within epsilon + QVariant c = caf::pdmToVariant( base + epsilon * 2.0 ); // outside epsilon + + EXPECT_TRUE( caf::pdmVariantEqual( a, b ) ); + EXPECT_FALSE( caf::pdmVariantEqual( a, c ) ); +} + +TEST( PdmFieldTraits, VariantEqual_Float_WithinEpsilon ) +{ + float base = 1.0f; + float epsilon = 1e-6f; + QVariant a = caf::pdmToVariant( base ); + QVariant b = caf::pdmToVariant( base + epsilon * 0.5f ); // within epsilon + QVariant c = caf::pdmToVariant( base + epsilon * 2.0f ); // outside epsilon + + EXPECT_TRUE( caf::pdmVariantEqual( a, b ) ); + EXPECT_FALSE( caf::pdmVariantEqual( a, c ) ); +} + +TEST( PdmFieldTraits, VariantEqual_FilePath ) +{ + QVariant a = caf::pdmToVariant( caf::FilePath( "/path/to/file.txt" ) ); + QVariant b = caf::pdmToVariant( caf::FilePath( "/path/to/file.txt" ) ); + QVariant c = caf::pdmToVariant( caf::FilePath( "/other/path.txt" ) ); + + EXPECT_TRUE( caf::pdmVariantEqual( a, b ) ); + EXPECT_FALSE( caf::pdmVariantEqual( a, c ) ); +} + +TEST( PdmFieldTraits, VariantEqual_AppEnum ) +{ + QVariant a = caf::pdmToVariant( caf::AppEnum( TraitTestEnum::ALPHA ) ); + QVariant b = caf::pdmToVariant( caf::AppEnum( TraitTestEnum::ALPHA ) ); + QVariant c = caf::pdmToVariant( caf::AppEnum( TraitTestEnum::GAMMA ) ); + + EXPECT_TRUE( caf::pdmVariantEqual>( a, b ) ); + EXPECT_FALSE( caf::pdmVariantEqual>( a, c ) ); +} + +TEST( PdmFieldTraits, VariantEqual_Vector_Equal ) +{ + std::vector v1 = { 1, 2, 3 }; + std::vector v2 = { 1, 2, 3 }; + QVariant a = caf::pdmToVariant( v1 ); + QVariant b = caf::pdmToVariant( v2 ); + + EXPECT_TRUE( caf::pdmVariantEqual>( a, b ) ); +} + +TEST( PdmFieldTraits, VariantEqual_Vector_DifferentSize ) +{ + std::vector v1 = { 1, 2, 3 }; + std::vector v2 = { 1, 2 }; + QVariant a = caf::pdmToVariant( v1 ); + QVariant b = caf::pdmToVariant( v2 ); + + EXPECT_FALSE( caf::pdmVariantEqual>( a, b ) ); +} + +TEST( PdmFieldTraits, VariantEqual_Vector_DifferentValues ) +{ + std::vector v1 = { 1, 2, 3 }; + std::vector v2 = { 1, 2, 99 }; + QVariant a = caf::pdmToVariant( v1 ); + QVariant b = caf::pdmToVariant( v2 ); + + EXPECT_FALSE( caf::pdmVariantEqual>( a, b ) ); +} + +TEST( PdmFieldTraits, VariantEqual_Vector_Double_UsesEpsilon ) +{ + double epsilon = 1e-8; + std::vector v1 = { 1.0, 2.0 }; + std::vector v2 = { 1.0 + epsilon * 0.5, 2.0 + epsilon * 0.5 }; // within epsilon + std::vector v3 = { 1.0 + epsilon * 2.0, 2.0 }; // outside epsilon + + QVariant a = caf::pdmToVariant( v1 ); + QVariant b = caf::pdmToVariant( v2 ); + QVariant c = caf::pdmToVariant( v3 ); + + EXPECT_TRUE( caf::pdmVariantEqual>( a, b ) ); + EXPECT_FALSE( caf::pdmVariantEqual>( a, c ) ); +} + +TEST( PdmFieldTraits, VariantEqual_Vector_Empty ) +{ + std::vector v1; + std::vector v2; + QVariant a = caf::pdmToVariant( v1 ); + QVariant b = caf::pdmToVariant( v2 ); + + EXPECT_TRUE( caf::pdmVariantEqual>( a, b ) ); +} + +TEST( PdmFieldTraits, VariantEqual_Pair_Equal ) +{ + auto p1 = std::make_pair( true, QString( "hello" ) ); + QVariant a = caf::pdmToVariant( p1 ); + QVariant b = caf::pdmToVariant( p1 ); + + EXPECT_TRUE( ( caf::pdmVariantEqual>( a, b ) ) ); +} + +TEST( PdmFieldTraits, VariantEqual_Pair_FirstDiffers ) +{ + QVariant a = caf::pdmToVariant( std::make_pair( true, QString( "hello" ) ) ); + QVariant b = caf::pdmToVariant( std::make_pair( false, QString( "hello" ) ) ); + + EXPECT_FALSE( ( caf::pdmVariantEqual>( a, b ) ) ); +} + +TEST( PdmFieldTraits, VariantEqual_Pair_SecondDiffers ) +{ + QVariant a = caf::pdmToVariant( std::make_pair( true, QString( "hello" ) ) ); + QVariant b = caf::pdmToVariant( std::make_pair( true, QString( "world" ) ) ); + + EXPECT_FALSE( ( caf::pdmVariantEqual>( a, b ) ) ); +} + +TEST( PdmFieldTraits, VariantEqual_Pair_Double_UsesEpsilon ) +{ + double epsilon = 1e-8; + QVariant a = caf::pdmToVariant( std::make_pair( true, 1.0 ) ); + QVariant b = caf::pdmToVariant( std::make_pair( true, 1.0 + epsilon * 0.5 ) ); // within + QVariant c = caf::pdmToVariant( std::make_pair( true, 1.0 + epsilon * 2.0 ) ); // outside + + EXPECT_TRUE( ( caf::pdmVariantEqual>( a, b ) ) ); + EXPECT_FALSE( ( caf::pdmVariantEqual>( a, c ) ) ); +} + +TEST( PdmFieldTraits, VariantEqual_PdmPointer_BothNull ) +{ + caf::PdmPointer p1; + caf::PdmPointer p2; + QVariant a = caf::pdmToVariant( p1 ); + QVariant b = caf::pdmToVariant( p2 ); + + EXPECT_TRUE( ( caf::pdmVariantEqual>( a, b ) ) ); +} + +TEST( PdmFieldTraits, VariantEqual_PdmPointer_NullVsNonNull ) +{ + auto obj = std::make_unique(); + caf::PdmPointer p1( obj.get() ); + caf::PdmPointer p2; + QVariant a = caf::pdmToVariant( p1 ); + QVariant b = caf::pdmToVariant( p2 ); + + EXPECT_FALSE( ( caf::pdmVariantEqual>( a, b ) ) ); +} + +TEST( PdmFieldTraits, VariantEqual_PdmPointer_SameObject ) +{ + auto obj = std::make_unique(); + caf::PdmPointer p1( obj.get() ); + caf::PdmPointer p2( obj.get() ); + QVariant a = caf::pdmToVariant( p1 ); + QVariant b = caf::pdmToVariant( p2 ); + + EXPECT_TRUE( ( caf::pdmVariantEqual>( a, b ) ) ); +} + +TEST( PdmFieldTraits, VariantEqual_PdmPointer_DifferentObjects ) +{ + auto obj1 = std::make_unique(); + auto obj2 = std::make_unique(); + caf::PdmPointer p1( obj1.get() ); + caf::PdmPointer p2( obj2.get() ); + QVariant a = caf::pdmToVariant( p1 ); + QVariant b = caf::pdmToVariant( p2 ); + + EXPECT_FALSE( ( caf::pdmVariantEqual>( a, b ) ) ); +} + +// ------------------------------------------------------------------------------------------------ +// std::optional round-trip tests +// ------------------------------------------------------------------------------------------------ + +TEST( PdmFieldTraits, RoundTrip_Optional_Double_HasValue ) +{ + std::optional orig = 3.14; + QVariant v = caf::pdmToVariant( orig ); + + std::optional decoded; + caf::pdmFromVariant( v, decoded ); + + ASSERT_TRUE( decoded.has_value() ); + EXPECT_DOUBLE_EQ( *orig, *decoded ); +} + +TEST( PdmFieldTraits, RoundTrip_Optional_Double_Nullopt ) +{ + std::optional orig; + QVariant v = caf::pdmToVariant( orig ); + + std::optional decoded = 99.0; + caf::pdmFromVariant( v, decoded ); + + EXPECT_FALSE( decoded.has_value() ); +} + +TEST( PdmFieldTraits, RoundTrip_Optional_QString_HasValue ) +{ + std::optional orig = QString( "hello" ); + QVariant v = caf::pdmToVariant( orig ); + + std::optional decoded; + caf::pdmFromVariant( v, decoded ); + + ASSERT_TRUE( decoded.has_value() ); + EXPECT_EQ( *orig, *decoded ); +} + +// ------------------------------------------------------------------------------------------------ +// std::optional equality tests +// ------------------------------------------------------------------------------------------------ + +TEST( PdmFieldTraits, VariantEqual_Optional_BothNullopt ) +{ + std::optional a; + std::optional b; + QVariant va = caf::pdmToVariant( a ); + QVariant vb = caf::pdmToVariant( b ); + + EXPECT_TRUE( ( caf::pdmVariantEqual>( va, vb ) ) ); +} + +TEST( PdmFieldTraits, VariantEqual_Optional_NulloptVsValue ) +{ + std::optional a; + std::optional b = 1.0; + QVariant va = caf::pdmToVariant( a ); + QVariant vb = caf::pdmToVariant( b ); + + EXPECT_FALSE( ( caf::pdmVariantEqual>( va, vb ) ) ); + EXPECT_FALSE( ( caf::pdmVariantEqual>( vb, va ) ) ); +} + +TEST( PdmFieldTraits, VariantEqual_Optional_SameValue ) +{ + std::optional a = 2.5; + std::optional b = 2.5; + QVariant va = caf::pdmToVariant( a ); + QVariant vb = caf::pdmToVariant( b ); + + EXPECT_TRUE( ( caf::pdmVariantEqual>( va, vb ) ) ); +} + +TEST( PdmFieldTraits, VariantEqual_Optional_DifferentValues ) +{ + std::optional a = 2.5; + std::optional b = 3.5; + QVariant va = caf::pdmToVariant( a ); + QVariant vb = caf::pdmToVariant( b ); + + EXPECT_FALSE( ( caf::pdmVariantEqual>( va, vb ) ) ); +} diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmDataValueField.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmDataValueField.h index 86a093cd777..5d00112142a 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmDataValueField.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmDataValueField.h @@ -40,7 +40,7 @@ #include "cafPdmValueField.h" #include "cafAssert.h" -#include "cafInternalPdmValueFieldSpecializations.h" +#include "cafPdmFieldTraits.h" #include "cafPdmUiFieldHandleInterface.h" #include @@ -123,12 +123,14 @@ class PdmDataValueField : public PdmValueField QVariant toQVariant() const override { CAF_ASSERT( isInitializedByInitFieldMacro() ); - return PdmValueFieldSpecialization::convert( m_fieldValue ); + using caf::pdmToVariant; + return pdmToVariant( m_fieldValue ); } void setFromQVariant( const QVariant& variant ) override { CAF_ASSERT( isInitializedByInitFieldMacro() ); - PdmValueFieldSpecialization::setFromVariant( variant, m_fieldValue ); + using caf::pdmFromVariant; + pdmFromVariant( variant, m_fieldValue ); } bool isReadOnly() const override { return false; } diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmFieldTraits.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmFieldTraits.h new file mode 100644 index 00000000000..e5cd4fda5db --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmFieldTraits.h @@ -0,0 +1,210 @@ +#pragma once + +#include + +#include +#include +#include +#include + +namespace caf +{ + +//================================================================================================== +/// pdmToVariant / pdmFromVariant +/// +/// ADL-based customization points for converting field values to/from QVariant. +/// The default implementations work for any Qt-metatype-registered type. +/// Add overloads in the caf namespace (or the type's own namespace) to support additional types. +//================================================================================================== + +template +QVariant pdmToVariant( const T& value ) +{ + return QVariant::fromValue( value ); +} + +template +void pdmFromVariant( const QVariant& v, T& out ) +{ + out = v.value(); +} + +//================================================================================================== +/// std::vector overloads — element-wise delegation +//================================================================================================== + +template +QVariant pdmToVariant( const std::vector& value ) +{ + QList list; + list.reserve( static_cast( value.size() ) ); + for ( const auto& element : value ) + { + using caf::pdmToVariant; + list.push_back( pdmToVariant( element ) ); + } + return list; +} + +template +void pdmFromVariant( const QVariant& v, std::vector& out ) +{ + if ( v.canConvert>() ) + { + out.clear(); + const QList list = v.toList(); + for ( const auto& item : list ) + { + T element; + using caf::pdmFromVariant; + pdmFromVariant( item, element ); + out.push_back( element ); + } + } +} + +//================================================================================================== +/// std::pair overloads +//================================================================================================== + +template +QVariant pdmToVariant( const std::pair& value ) +{ + using caf::pdmToVariant; + QList list; + list.push_back( pdmToVariant( value.first ) ); + list.push_back( pdmToVariant( value.second ) ); + return list; +} + +template +void pdmFromVariant( const QVariant& v, std::pair& out ) +{ + if ( v.canConvert>() ) + { + const QList list = v.toList(); + if ( list.size() == 2 ) + { + using caf::pdmFromVariant; + pdmFromVariant( list[0], out.first ); + pdmFromVariant( list[1], out.second ); + } + } +} + +//================================================================================================== +/// std::optional overloads +/// Convention: nullopt -> invalid QVariant(); has value -> pdmToVariant(*val) +//================================================================================================== + +template +QVariant pdmToVariant( const std::optional& value ) +{ + if ( !value.has_value() ) return QVariant(); + using caf::pdmToVariant; + return pdmToVariant( *value ); +} + +template +void pdmFromVariant( const QVariant& v, std::optional& out ) +{ + if ( !v.isValid() ) + { + out.reset(); + return; + } + T underlying; + using caf::pdmFromVariant; + pdmFromVariant( v, underlying ); + out = underlying; +} + +//================================================================================================== +/// PdmVariantEqualImpl +/// +/// Class template used for comparing two QVariants carrying a field value of type T. +/// Partial specializations handle containers and composites. +/// Full specializations (e.g. for float, double, FilePath, cvf types) provide type-specific logic. +/// Extend by specializing PdmVariantEqualImpl in the header that defines YourType. +//================================================================================================== + +template +struct PdmVariantEqualImpl +{ + static bool equal( const QVariant& a, const QVariant& b ) { return a.value() == b.value(); } +}; + +template +struct PdmVariantEqualImpl> +{ + static bool equal( const QVariant& a, const QVariant& b ) + { + const QList la = a.toList(); + const QList lb = b.toList(); + if ( la.size() != lb.size() ) return false; + for ( int i = 0; i < la.size(); ++i ) + if ( !PdmVariantEqualImpl::equal( la[i], lb[i] ) ) return false; + return true; + } +}; + +template +struct PdmVariantEqualImpl> +{ + static bool equal( const QVariant& a, const QVariant& b ) + { + const QList la = a.toList(); + const QList lb = b.toList(); + if ( la.size() != 2 || lb.size() != 2 ) return false; + return PdmVariantEqualImpl::equal( la[0], lb[0] ) && PdmVariantEqualImpl::equal( la[1], lb[1] ); + } +}; + +template +struct PdmVariantEqualImpl> +{ + static bool equal( const QVariant& a, const QVariant& b ) + { + // pdmToVariant(nullopt) always produces an invalid QVariant() + const bool aEmpty = !a.isValid(); + const bool bEmpty = !b.isValid(); + if ( aEmpty && bEmpty ) return true; + if ( aEmpty != bEmpty ) return false; + return PdmVariantEqualImpl::equal( a, b ); + } +}; + +template <> +struct PdmVariantEqualImpl +{ + static bool equal( const QVariant& a, const QVariant& b ) + { + // See PdmFieldWriter::writeFieldData for the precision used when writing float values + const float epsilon = 1e-6f; + return qAbs( a.value() - b.value() ) < epsilon; + } +}; + +template <> +struct PdmVariantEqualImpl +{ + static bool equal( const QVariant& a, const QVariant& b ) + { + // See PdmFieldWriter::writeFieldData for the precision used when writing double values + const double epsilon = 1e-8; + return qAbs( a.value() - b.value() ) < epsilon; + } +}; + +//================================================================================================== +/// pdmVariantEqual — public API, delegates to PdmVariantEqualImpl +//================================================================================================== + +template +bool pdmVariantEqual( const QVariant& a, const QVariant& b ) +{ + return PdmVariantEqualImpl::equal( a, b ); +} + +} // namespace caf diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmPointer.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmPointer.h index 203927497fa..be80f9d191f 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmPointer.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmPointer.h @@ -132,3 +132,33 @@ class PdmPointer #include Q_DECLARE_METATYPE( caf::PdmPointer ); + +#include "cafPdmFieldTraits.h" + +#include + +namespace caf +{ + +template +QVariant pdmToVariant( const PdmPointer& value ) +{ + return QVariant::fromValue( PdmPointer( value.rawPtr() ) ); +} + +template +void pdmFromVariant( const QVariant& v, PdmPointer& out ) +{ + out.setRawPtr( v.value>().rawPtr() ); +} + +template +struct PdmVariantEqualImpl> +{ + static bool equal( const QVariant& a, const QVariant& b ) + { + return a.value>() == b.value>(); + } +}; + +} // namespace caf diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmProxyValueField.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmProxyValueField.h index fff51ad7ee5..cde411a4331 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmProxyValueField.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmProxyValueField.h @@ -1,8 +1,8 @@ #pragma once #include "cafAssert.h" -#include "cafInternalPdmValueFieldSpecializations.h" #include "cafPdmFieldHandle.h" +#include "cafPdmFieldTraits.h" #include "cafPdmPointer.h" #include "cafPdmValueField.h" @@ -88,12 +88,14 @@ class PdmProxyValueField : public PdmProxyFieldHandle QVariant toQVariant() const override { DataType val = value(); - return PdmValueFieldSpecialization::convert( val ); + using caf::pdmToVariant; + return pdmToVariant( val ); } void setFromQVariant( const QVariant& variant ) override { DataType val; - PdmValueFieldSpecialization::setFromVariant( variant, val ); + using caf::pdmFromVariant; + pdmFromVariant( variant, val ); setValue( val ); } bool isReadOnly() const override diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafFontTools.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafFontTools.cpp index 14825043326..79194c77d8b 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafFontTools.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafFontTools.cpp @@ -37,6 +37,7 @@ #include "cafAppEnum.h" #include "cafPdmObjectHandle.h" +#include "cafPdmOptionItemInfo.h" #include "cafPdmUiItem.h" #include diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafIconProvider.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafIconProvider.cpp index 08aa84b5aef..af9f0a72f80 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafIconProvider.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafIconProvider.cpp @@ -36,12 +36,16 @@ #include "cafIconProvider.h" #include +#include #include #include +#include #include using namespace caf; +IconProvider::~IconProvider() = default; + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafIconProvider.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafIconProvider.h index 58b0206f867..d4e84c04e71 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafIconProvider.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafIconProvider.h @@ -35,8 +35,6 @@ //################################################################################################## #pragma once -#include -#include #include #include @@ -59,6 +57,7 @@ class IconProvider IconProvider( const QString& iconResourceString, const QSize& preferredSize = QSize( 16, 16 ) ); IconProvider( const QPixmap& pixmap ); IconProvider( const IconProvider& rhs ); + ~IconProvider(); IconProvider& operator=( const IconProvider& rhs ); void setActive( bool active ); diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafInternalPdmFieldTypeSpecializations.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafInternalPdmFieldTypeSpecializations.h index fa3f406daa3..0df6615b303 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafInternalPdmFieldTypeSpecializations.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafInternalPdmFieldTypeSpecializations.h @@ -1,77 +1,48 @@ #pragma once -#include "cafInternalPdmValueFieldSpecializations.h" -#include "cafPdmObjectHandle.h" +#include "cafAppEnum.h" +#include "cafPdmFieldTraits.h" #include "cafPdmPointer.h" namespace caf { template class PdmDataValueField; -template -class PdmPointer; -template -class AppEnum; //================================================================================================== -/// Helper base class for types that delegate all operations to PdmValueFieldSpecialization. +/// Helper base class for types that delegate all operations to pdmToVariant/pdmFromVariant/pdmVariantEqual. /// Inherit from this to avoid repeating the delegation boilerplate. //================================================================================================== template struct PdmUiFieldSpecializationForValueSpec : public PdmUiFieldSpecializationDefaults { - static QVariant convert( const T& value ) { return PdmValueFieldSpecialization::convert( value ); } + static QVariant convert( const T& value ) + { + using caf::pdmToVariant; + return pdmToVariant( value ); + } static void setFromVariant( const QVariant& variantValue, T& value ) { - PdmValueFieldSpecialization::setFromVariant( variantValue, value ); + using caf::pdmFromVariant; + pdmFromVariant( variantValue, value ); } static bool isDataElementEqual( const QVariant& variantValue, const QVariant& variantValue2 ) { - return PdmValueFieldSpecialization::isEqual( variantValue, variantValue2 ); + return caf::pdmVariantEqual( variantValue, variantValue2 ); } }; //================================================================================================== -/// Primary template - delegates to PdmValueFieldSpecialization. -/// Types with custom PdmValueFieldSpecialization will automatically get correct behavior. +/// Primary template - delegates to pdmToVariant/pdmFromVariant/pdmVariantEqual. +/// Types with custom overloads of those functions will automatically get correct behavior. //================================================================================================== template class PdmUiFieldSpecialization : public PdmUiFieldSpecializationForValueSpec { }; -//================================================================================================== -/// Partial specialization for PdmField< PdmPointer > -/// -/// Will package the PdmPointer into QVariant as PdmPointer -/// Needed to support arbitrary types in PdmPointer without -/// havning to declare everything Q_DECLARE_METATYPE() -/// Also introduces the need for a isEqual() method, as this was the first -/// custom type embedded in QVariant -//================================================================================================== - -template -class PdmUiFieldSpecialization> : public PdmUiFieldSpecializationDefaults -{ -public: - static QVariant convert( const PdmPointer& value ) - { - return QVariant::fromValue( PdmPointer( value.rawPtr() ) ); - } - - static void setFromVariant( const QVariant& variantValue, PdmPointer& value ) - { - value.setRawPtr( variantValue.value>().rawPtr() ); - } - - static bool isDataElementEqual( const QVariant& variantValue, const QVariant& variantValue2 ) - { - return variantValue.value>() == variantValue2.value>(); - } -}; - //================================================================================================== /// Partial specialization for PdmField< std::list > //================================================================================================== @@ -82,11 +53,11 @@ class PdmUiFieldSpecialization> : public PdmUiFieldSpecializationDe public: static QVariant convert( const std::list& value ) { - QList returnList; - typename std::list::const_iterator it; - for ( it = value.begin(); it != value.end(); ++it ) + QList returnList; + for ( const auto& item : value ) { - returnList.push_back( QVariant( *it ) ); + using caf::pdmToVariant; + returnList.push_back( pdmToVariant( item ) ); } return returnList; } @@ -96,18 +67,20 @@ class PdmUiFieldSpecialization> : public PdmUiFieldSpecializationDe if ( variantValue.canConvert>() ) { value.clear(); - QList lst = variantValue.toList(); - int i; - for ( i = 0; i < lst.size(); ++i ) + const QList lst = variantValue.toList(); + for ( const auto& item : lst ) { - value.push_back( lst[i].value() ); + T element; + using caf::pdmFromVariant; + pdmFromVariant( item, element ); + value.push_back( element ); } } } static bool isDataElementEqual( const QVariant& variantValue, const QVariant& variantValue2 ) { - return PdmValueFieldSpecialization::isEqual( variantValue, variantValue2 ); + return caf::pdmVariantEqual( variantValue, variantValue2 ); } }; @@ -121,17 +94,19 @@ class PdmUiFieldSpecialization> : public PdmUiFieldSpecialization public: static QVariant convert( const std::vector& value ) { - return PdmValueFieldSpecialization>::convert( value ); + using caf::pdmToVariant; + return pdmToVariant( value ); } static void setFromVariant( const QVariant& variantValue, std::vector& value ) { - return PdmValueFieldSpecialization>::setFromVariant( variantValue, value ); + using caf::pdmFromVariant; + pdmFromVariant( variantValue, value ); } static bool isDataElementEqual( const QVariant& variantValue, const QVariant& variantValue2 ) { - return PdmValueFieldSpecialization::isEqual( variantValue, variantValue2 ); + return caf::pdmVariantEqual( variantValue, variantValue2 ); } }; @@ -142,17 +117,11 @@ template class PdmUiFieldSpecialization> : public PdmUiFieldSpecializationDefaults { public: - static QVariant convert( const caf::AppEnum& value ) - { - T enumVal = value; - - // Explicit cast to an int for storage in a QVariant. This allows the use of enum class instead of enum - return QVariant( static_cast( enumVal ) ); - } + static QVariant convert( const caf::AppEnum& value ) { return caf::pdmToVariant( value ); } static void setFromVariant( const QVariant& variantValue, caf::AppEnum& value ) { - value = static_cast( variantValue.toInt() ); + caf::pdmFromVariant( variantValue, value ); } static QList valueOptions( PdmFieldHandle* fieldHandle, const caf::AppEnum& appEnum ) @@ -187,48 +156,14 @@ class PdmUiFieldSpecialization> : public PdmUiFieldSpecializatio public: static QVariant convert( const std::pair& value ) { - return PdmValueFieldSpecialization>::convert( value ); + using caf::pdmToVariant; + return pdmToVariant( value ); } static void setFromVariant( const QVariant& variantValue, std::pair& value ) { - PdmValueFieldSpecialization>::setFromVariant( variantValue, value ); - } -}; - -//================================================================================================== -/// Partial specialization for PdmField>> -//================================================================================================== -template -class PdmUiFieldSpecialization> : public PdmUiFieldSpecializationDefaults -{ -public: - /// Convert the field value into a QVariant - static QVariant convert( const std::optional& value ) - { - if ( value.has_value() ) - { - return PdmValueFieldSpecialization::convert( value.value() ); - } - - return QVariant(); - } - - /// Set the field value from a QVariant - static void setFromVariant( const QVariant& variantValue, std::optional& value ) - { - // An empty QVariant means no value, and we should set the optional to std::nullopt - auto stringText = variantValue.toString(); - stringText.remove( '"' ); - if ( stringText.isEmpty() ) - { - value.reset(); - return; - } - - T valueOfType; - PdmValueFieldSpecialization::setFromVariant( variantValue, valueOfType ); - value = valueOfType; + using caf::pdmFromVariant; + pdmFromVariant( variantValue, value ); } }; diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafInternalPdmUiFieldCapability.inl b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafInternalPdmUiFieldCapability.inl index 03b9e4adc33..93aac78370c 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafInternalPdmUiFieldCapability.inl +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafInternalPdmUiFieldCapability.inl @@ -283,7 +283,7 @@ template bool PdmFieldUiCap::isQVariantDataEqual( const QVariant& oldUiBasedQVariant, const QVariant& newUiBasedQVariant ) const { - return PdmValueFieldSpecialization::isEqual( oldUiBasedQVariant, newUiBasedQVariant ); + return caf::pdmVariantEqual( oldUiBasedQVariant, newUiBasedQVariant ); } } // End of namespace caf diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmOptionItemInfo.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmOptionItemInfo.cpp index 49e09fd964a..c28f144379a 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmOptionItemInfo.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmOptionItemInfo.cpp @@ -36,6 +36,8 @@ #include "cafPdmOptionItemInfo.h" +#include + #include "cafPdmObjectHandle.h" #include "cafPdmPointer.h" diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUi3dObjectEditorHandle.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUi3dObjectEditorHandle.h index 35054e4b5b3..26098ad3ddc 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUi3dObjectEditorHandle.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUi3dObjectEditorHandle.h @@ -46,6 +46,8 @@ // -<| PdmUi3dObjectEditorHandle namespace caf { +class PdmUiFieldHandle; + //================================================================================================== /// Macros helping in development of PDM UI 3d editors //================================================================================================== diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiEditorHandle.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiEditorHandle.cpp index 00548a9485c..bad49eace10 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiEditorHandle.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiEditorHandle.cpp @@ -36,6 +36,8 @@ #include "cafPdmUiEditorHandle.h" +#include "cafAssert.h" + namespace caf { //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiFieldEditorHandle.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiFieldEditorHandle.h index 3aa66d8d399..debcf25fc73 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiFieldEditorHandle.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiFieldEditorHandle.h @@ -39,6 +39,8 @@ #include "cafFactory.h" #include "cafPdmUiEditorHandle.h" +#include + class QAction; class QLabel; @@ -75,6 +77,7 @@ public: \ QString, \ qStringTypeName( caf::PdmProxyValueField ) ) +class PdmFieldHandle; class PdmUiGroup; class PdmUiFieldHandle; diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiFieldHandle.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiFieldHandle.cpp index a95cdfe44e5..8fb5de2c10b 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiFieldHandle.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiFieldHandle.cpp @@ -2,6 +2,7 @@ #include "cafAssert.h" #include "cafPdmFieldHandle.h" +#include "cafPdmObjectHandle.h" #include "cafPdmUiEditorHandle.h" #include "cafPdmUiModelChangeDetector.h" #include "cafPdmUiObjectHandle.h" diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiFieldHandle.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiFieldHandle.h index 65a36b67803..3eb50d37e6e 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiFieldHandle.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiFieldHandle.h @@ -1,6 +1,7 @@ #pragma once #include "cafPdmFieldCapability.h" +#include "cafPdmOptionItemInfo.h" #include "cafPdmUiFieldHandleInterface.h" #include "cafPdmUiItem.h" diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiFieldSpecialization.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiFieldSpecialization.h index 509d1a0cead..25ba3ae8e97 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiFieldSpecialization.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiFieldSpecialization.h @@ -46,8 +46,8 @@ struct PdmUiFieldSpecializationDefaults /// When introducing a new type in a PdmField, you might need to implement a (partial)specialization /// of this class. /// -/// The primary template delegates to PdmValueFieldSpecialization, so types with custom -/// PdmValueFieldSpecialization will automatically get the correct behavior without needing +/// The primary template delegates to pdmToVariant/pdmFromVariant/pdmVariantEqual, so types with +/// custom overloads of those functions will automatically get the correct behavior without needing /// an explicit PdmUiFieldSpecialization. //================================================================================================== diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiItem.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiItem.cpp index 187e095ed01..0f6a124805a 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiItem.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiItem.cpp @@ -35,12 +35,14 @@ //################################################################################################## #include "cafPdmUiItem.h" + #include "cafPdmLogging.h" #include "cafPdmOptionItemInfo.h" #include "cafPdmUiEditorHandle.h" #include "cafPdmUiItemInfo.h" #include "cafPdmUiObjectEditorHandle.h" #include "cafUpdateEditorsScheduler.h" +#include namespace caf { diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiItemInfo.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiItemInfo.cpp index 866075b4958..5a74390554c 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiItemInfo.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiItemInfo.cpp @@ -36,6 +36,8 @@ #include "cafPdmUiItemInfo.h" +#include + namespace caf { //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiItemInfo.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiItemInfo.h index bc466dfcfa9..c51adfc18e2 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiItemInfo.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiItemInfo.h @@ -38,6 +38,8 @@ #include "cafIconProvider.h" +#include + #include #include diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiObjectHandle.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiObjectHandle.h index c17447eb652..6e8e0ebe750 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiObjectHandle.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiObjectHandle.h @@ -1,6 +1,7 @@ #pragma once #include "cafPdmObjectCapability.h" +#include "cafPdmOptionItemInfo.h" #include "cafPdmUiItem.h" class QMenu; diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/CMakeLists.txt b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/CMakeLists.txt new file mode 100644 index 00000000000..d9709776c8e --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.15) + +project(cafPdm_CompileBench) + +find_package( + Qt6 + COMPONENTS + REQUIRED Core Widgets +) +qt_standard_project_setup() + +set(PROJECT_FILES + bench_basic_fields.cpp bench_enum_fields.cpp bench_container_fields.cpp + bench_filepath_fields.cpp bench_mixed_fields.cpp +) + +# OBJECT library: compiles each file individually without linking. This isolates +# the compile-time cost per translation unit. +add_library(${PROJECT_NAME} OBJECT ${PROJECT_FILES}) + +# Disable unity build for this target — each file must compile independently +set_target_properties(${PROJECT_NAME} PROPERTIES UNITY_BUILD OFF) + +target_link_libraries( + ${PROJECT_NAME} PRIVATE cafProjectDataModel Qt6::Core Qt6::Widgets +) diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_basic_fields.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_basic_fields.cpp new file mode 100644 index 00000000000..6cbe872bfdb --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_basic_fields.cpp @@ -0,0 +1,59 @@ +// Compile-time benchmark: PdmObjects with basic field types (int, double, bool, QString) +// Used to measure the compile-time cost of cafPdmField.h and cafPdmFieldTraits.h + +#include "cafPdmField.h" +#include "cafPdmObject.h" + +#include + +// clang-format off + +#define BENCH_BASIC_OBJECT( N ) \ +class BenchBasicObj##N : public caf::PdmObject \ +{ \ + CAF_PDM_HEADER_INIT; \ +public: \ + BenchBasicObj##N() \ + { \ + CAF_PDM_InitObject( "BenchBasicObj" #N ); \ + CAF_PDM_InitField( &m_intA, "IntA", 0, "Int A" ); \ + CAF_PDM_InitField( &m_intB, "IntB", 0, "Int B" ); \ + CAF_PDM_InitField( &m_dblA, "DblA", 0.0, "Double A" ); \ + CAF_PDM_InitField( &m_dblB, "DblB", 0.0, "Double B" ); \ + CAF_PDM_InitField( &m_boolA, "BoolA", false, "Bool A" ); \ + CAF_PDM_InitField( &m_boolB, "BoolB", false, "Bool B" ); \ + CAF_PDM_InitField( &m_strA, "StrA", QString(), "String A" ); \ + CAF_PDM_InitField( &m_strB, "StrB", QString(), "String B" ); \ + } \ + caf::PdmField m_intA; \ + caf::PdmField m_intB; \ + caf::PdmField m_dblA; \ + caf::PdmField m_dblB; \ + caf::PdmField m_boolA; \ + caf::PdmField m_boolB; \ + caf::PdmField m_strA; \ + caf::PdmField m_strB; \ +}; + +BENCH_BASIC_OBJECT( 01 ) CAF_PDM_SOURCE_INIT( BenchBasicObj01, "BenchBasicObj01" ); +BENCH_BASIC_OBJECT( 02 ) CAF_PDM_SOURCE_INIT( BenchBasicObj02, "BenchBasicObj02" ); +BENCH_BASIC_OBJECT( 03 ) CAF_PDM_SOURCE_INIT( BenchBasicObj03, "BenchBasicObj03" ); +BENCH_BASIC_OBJECT( 04 ) CAF_PDM_SOURCE_INIT( BenchBasicObj04, "BenchBasicObj04" ); +BENCH_BASIC_OBJECT( 05 ) CAF_PDM_SOURCE_INIT( BenchBasicObj05, "BenchBasicObj05" ); +BENCH_BASIC_OBJECT( 06 ) CAF_PDM_SOURCE_INIT( BenchBasicObj06, "BenchBasicObj06" ); +BENCH_BASIC_OBJECT( 07 ) CAF_PDM_SOURCE_INIT( BenchBasicObj07, "BenchBasicObj07" ); +BENCH_BASIC_OBJECT( 08 ) CAF_PDM_SOURCE_INIT( BenchBasicObj08, "BenchBasicObj08" ); +BENCH_BASIC_OBJECT( 09 ) CAF_PDM_SOURCE_INIT( BenchBasicObj09, "BenchBasicObj09" ); +BENCH_BASIC_OBJECT( 10 ) CAF_PDM_SOURCE_INIT( BenchBasicObj10, "BenchBasicObj10" ); +BENCH_BASIC_OBJECT( 11 ) CAF_PDM_SOURCE_INIT( BenchBasicObj11, "BenchBasicObj11" ); +BENCH_BASIC_OBJECT( 12 ) CAF_PDM_SOURCE_INIT( BenchBasicObj12, "BenchBasicObj12" ); +BENCH_BASIC_OBJECT( 13 ) CAF_PDM_SOURCE_INIT( BenchBasicObj13, "BenchBasicObj13" ); +BENCH_BASIC_OBJECT( 14 ) CAF_PDM_SOURCE_INIT( BenchBasicObj14, "BenchBasicObj14" ); +BENCH_BASIC_OBJECT( 15 ) CAF_PDM_SOURCE_INIT( BenchBasicObj15, "BenchBasicObj15" ); +BENCH_BASIC_OBJECT( 16 ) CAF_PDM_SOURCE_INIT( BenchBasicObj16, "BenchBasicObj16" ); +BENCH_BASIC_OBJECT( 17 ) CAF_PDM_SOURCE_INIT( BenchBasicObj17, "BenchBasicObj17" ); +BENCH_BASIC_OBJECT( 18 ) CAF_PDM_SOURCE_INIT( BenchBasicObj18, "BenchBasicObj18" ); +BENCH_BASIC_OBJECT( 19 ) CAF_PDM_SOURCE_INIT( BenchBasicObj19, "BenchBasicObj19" ); +BENCH_BASIC_OBJECT( 20 ) CAF_PDM_SOURCE_INIT( BenchBasicObj20, "BenchBasicObj20" ); + +// clang-format on diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_container_fields.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_container_fields.cpp new file mode 100644 index 00000000000..36c863d8615 --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_container_fields.cpp @@ -0,0 +1,61 @@ +// Compile-time benchmark: PdmObjects with container field types +// Used to measure the compile-time cost of std::vector, std::optional, std::pair specializations + +#include "cafPdmField.h" +#include "cafPdmObject.h" + +#include +#include +#include + +// clang-format off + +#define BENCH_CONTAINER_OBJECT( N ) \ +class BenchContainerObj##N : public caf::PdmObject \ +{ \ + CAF_PDM_HEADER_INIT; \ +public: \ + BenchContainerObj##N() \ + { \ + CAF_PDM_InitObject( "BenchContainerObj" #N ); \ + CAF_PDM_InitFieldNoDefault( &m_vecDouble, "VecDouble", "Vector of doubles" ); \ + CAF_PDM_InitFieldNoDefault( &m_vecInt, "VecInt", "Vector of ints" ); \ + CAF_PDM_InitFieldNoDefault( &m_vecString, "VecString", "Vector of strings" ); \ + CAF_PDM_InitFieldNoDefault( &m_optDouble, "OptDouble", "Optional double" ); \ + CAF_PDM_InitFieldNoDefault( &m_optString, "OptString", "Optional string" ); \ + auto pairInit = std::make_pair( false, 0.0 ); \ + CAF_PDM_InitField( &m_pairBoolDbl, "PairBoolDbl", pairInit, "Pair bool/double" ); \ + auto pairStrInit = std::make_pair( false, QString() ); \ + CAF_PDM_InitField( &m_pairBoolStr, "PairBoolStr", pairStrInit, "Pair bool/string" ); \ + } \ + caf::PdmField> m_vecDouble; \ + caf::PdmField> m_vecInt; \ + caf::PdmField> m_vecString; \ + caf::PdmField> m_optDouble; \ + caf::PdmField> m_optString; \ + caf::PdmField> m_pairBoolDbl; \ + caf::PdmField> m_pairBoolStr; \ +}; + +BENCH_CONTAINER_OBJECT( 01 ) CAF_PDM_SOURCE_INIT( BenchContainerObj01, "BenchContainerObj01" ); +BENCH_CONTAINER_OBJECT( 02 ) CAF_PDM_SOURCE_INIT( BenchContainerObj02, "BenchContainerObj02" ); +BENCH_CONTAINER_OBJECT( 03 ) CAF_PDM_SOURCE_INIT( BenchContainerObj03, "BenchContainerObj03" ); +BENCH_CONTAINER_OBJECT( 04 ) CAF_PDM_SOURCE_INIT( BenchContainerObj04, "BenchContainerObj04" ); +BENCH_CONTAINER_OBJECT( 05 ) CAF_PDM_SOURCE_INIT( BenchContainerObj05, "BenchContainerObj05" ); +BENCH_CONTAINER_OBJECT( 06 ) CAF_PDM_SOURCE_INIT( BenchContainerObj06, "BenchContainerObj06" ); +BENCH_CONTAINER_OBJECT( 07 ) CAF_PDM_SOURCE_INIT( BenchContainerObj07, "BenchContainerObj07" ); +BENCH_CONTAINER_OBJECT( 08 ) CAF_PDM_SOURCE_INIT( BenchContainerObj08, "BenchContainerObj08" ); +BENCH_CONTAINER_OBJECT( 09 ) CAF_PDM_SOURCE_INIT( BenchContainerObj09, "BenchContainerObj09" ); +BENCH_CONTAINER_OBJECT( 10 ) CAF_PDM_SOURCE_INIT( BenchContainerObj10, "BenchContainerObj10" ); +BENCH_CONTAINER_OBJECT( 11 ) CAF_PDM_SOURCE_INIT( BenchContainerObj11, "BenchContainerObj11" ); +BENCH_CONTAINER_OBJECT( 12 ) CAF_PDM_SOURCE_INIT( BenchContainerObj12, "BenchContainerObj12" ); +BENCH_CONTAINER_OBJECT( 13 ) CAF_PDM_SOURCE_INIT( BenchContainerObj13, "BenchContainerObj13" ); +BENCH_CONTAINER_OBJECT( 14 ) CAF_PDM_SOURCE_INIT( BenchContainerObj14, "BenchContainerObj14" ); +BENCH_CONTAINER_OBJECT( 15 ) CAF_PDM_SOURCE_INIT( BenchContainerObj15, "BenchContainerObj15" ); +BENCH_CONTAINER_OBJECT( 16 ) CAF_PDM_SOURCE_INIT( BenchContainerObj16, "BenchContainerObj16" ); +BENCH_CONTAINER_OBJECT( 17 ) CAF_PDM_SOURCE_INIT( BenchContainerObj17, "BenchContainerObj17" ); +BENCH_CONTAINER_OBJECT( 18 ) CAF_PDM_SOURCE_INIT( BenchContainerObj18, "BenchContainerObj18" ); +BENCH_CONTAINER_OBJECT( 19 ) CAF_PDM_SOURCE_INIT( BenchContainerObj19, "BenchContainerObj19" ); +BENCH_CONTAINER_OBJECT( 20 ) CAF_PDM_SOURCE_INIT( BenchContainerObj20, "BenchContainerObj20" ); + +// clang-format on diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_enum_fields.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_enum_fields.cpp new file mode 100644 index 00000000000..993293bbd32 --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_enum_fields.cpp @@ -0,0 +1,50 @@ +// Compile-time benchmark: PdmObjects with caf::AppEnum field types +// Used to measure the compile-time cost of AppEnum template instantiation + +#include "cafAppEnum.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" + +// clang-format off + +// Each object gets its own enum to exercise distinct AppEnum instantiations +#define BENCH_ENUM_OBJECT( N ) \ +enum class BenchEnum##N { ValueA, ValueB, ValueC, ValueD }; \ +class BenchEnumObj##N : public caf::PdmObject \ +{ \ + CAF_PDM_HEADER_INIT; \ +public: \ + BenchEnumObj##N() \ + { \ + CAF_PDM_InitObject( "BenchEnumObj" #N ); \ + CAF_PDM_InitField( &m_enumA, "EnumA", BenchEnum##N::ValueA, "Enum A" ); \ + CAF_PDM_InitField( &m_enumB, "EnumB", BenchEnum##N::ValueB, "Enum B" ); \ + CAF_PDM_InitField( &m_enumC, "EnumC", BenchEnum##N::ValueC, "Enum C" ); \ + } \ + caf::PdmField> m_enumA; \ + caf::PdmField> m_enumB; \ + caf::PdmField> m_enumC; \ +}; + +BENCH_ENUM_OBJECT( 01 ) CAF_PDM_SOURCE_INIT( BenchEnumObj01, "BenchEnumObj01" ); +BENCH_ENUM_OBJECT( 02 ) CAF_PDM_SOURCE_INIT( BenchEnumObj02, "BenchEnumObj02" ); +BENCH_ENUM_OBJECT( 03 ) CAF_PDM_SOURCE_INIT( BenchEnumObj03, "BenchEnumObj03" ); +BENCH_ENUM_OBJECT( 04 ) CAF_PDM_SOURCE_INIT( BenchEnumObj04, "BenchEnumObj04" ); +BENCH_ENUM_OBJECT( 05 ) CAF_PDM_SOURCE_INIT( BenchEnumObj05, "BenchEnumObj05" ); +BENCH_ENUM_OBJECT( 06 ) CAF_PDM_SOURCE_INIT( BenchEnumObj06, "BenchEnumObj06" ); +BENCH_ENUM_OBJECT( 07 ) CAF_PDM_SOURCE_INIT( BenchEnumObj07, "BenchEnumObj07" ); +BENCH_ENUM_OBJECT( 08 ) CAF_PDM_SOURCE_INIT( BenchEnumObj08, "BenchEnumObj08" ); +BENCH_ENUM_OBJECT( 09 ) CAF_PDM_SOURCE_INIT( BenchEnumObj09, "BenchEnumObj09" ); +BENCH_ENUM_OBJECT( 10 ) CAF_PDM_SOURCE_INIT( BenchEnumObj10, "BenchEnumObj10" ); +BENCH_ENUM_OBJECT( 11 ) CAF_PDM_SOURCE_INIT( BenchEnumObj11, "BenchEnumObj11" ); +BENCH_ENUM_OBJECT( 12 ) CAF_PDM_SOURCE_INIT( BenchEnumObj12, "BenchEnumObj12" ); +BENCH_ENUM_OBJECT( 13 ) CAF_PDM_SOURCE_INIT( BenchEnumObj13, "BenchEnumObj13" ); +BENCH_ENUM_OBJECT( 14 ) CAF_PDM_SOURCE_INIT( BenchEnumObj14, "BenchEnumObj14" ); +BENCH_ENUM_OBJECT( 15 ) CAF_PDM_SOURCE_INIT( BenchEnumObj15, "BenchEnumObj15" ); +BENCH_ENUM_OBJECT( 16 ) CAF_PDM_SOURCE_INIT( BenchEnumObj16, "BenchEnumObj16" ); +BENCH_ENUM_OBJECT( 17 ) CAF_PDM_SOURCE_INIT( BenchEnumObj17, "BenchEnumObj17" ); +BENCH_ENUM_OBJECT( 18 ) CAF_PDM_SOURCE_INIT( BenchEnumObj18, "BenchEnumObj18" ); +BENCH_ENUM_OBJECT( 19 ) CAF_PDM_SOURCE_INIT( BenchEnumObj19, "BenchEnumObj19" ); +BENCH_ENUM_OBJECT( 20 ) CAF_PDM_SOURCE_INIT( BenchEnumObj20, "BenchEnumObj20" ); + +// clang-format on diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_filepath_fields.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_filepath_fields.cpp new file mode 100644 index 00000000000..9bf9887f524 --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_filepath_fields.cpp @@ -0,0 +1,52 @@ +// Compile-time benchmark: PdmObjects with caf::FilePath field types +// Used to measure the compile-time cost of cafFilePath.h specializations + +#include "cafFilePath.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" + +#include + +// clang-format off + +#define BENCH_FILEPATH_OBJECT( N ) \ +class BenchFilePathObj##N : public caf::PdmObject \ +{ \ + CAF_PDM_HEADER_INIT; \ +public: \ + BenchFilePathObj##N() \ + { \ + CAF_PDM_InitObject( "BenchFilePathObj" #N ); \ + CAF_PDM_InitFieldNoDefault( &m_fileA, "FileA", "File A" ); \ + CAF_PDM_InitFieldNoDefault( &m_fileB, "FileB", "File B" ); \ + CAF_PDM_InitFieldNoDefault( &m_fileC, "FileC", "File C" ); \ + CAF_PDM_InitFieldNoDefault( &m_files, "Files", "File list" ); \ + } \ + caf::PdmField m_fileA; \ + caf::PdmField m_fileB; \ + caf::PdmField m_fileC; \ + caf::PdmField> m_files; \ +}; + +BENCH_FILEPATH_OBJECT( 01 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj01, "BenchFilePathObj01" ); +BENCH_FILEPATH_OBJECT( 02 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj02, "BenchFilePathObj02" ); +BENCH_FILEPATH_OBJECT( 03 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj03, "BenchFilePathObj03" ); +BENCH_FILEPATH_OBJECT( 04 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj04, "BenchFilePathObj04" ); +BENCH_FILEPATH_OBJECT( 05 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj05, "BenchFilePathObj05" ); +BENCH_FILEPATH_OBJECT( 06 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj06, "BenchFilePathObj06" ); +BENCH_FILEPATH_OBJECT( 07 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj07, "BenchFilePathObj07" ); +BENCH_FILEPATH_OBJECT( 08 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj08, "BenchFilePathObj08" ); +BENCH_FILEPATH_OBJECT( 09 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj09, "BenchFilePathObj09" ); +BENCH_FILEPATH_OBJECT( 10 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj10, "BenchFilePathObj10" ); +BENCH_FILEPATH_OBJECT( 11 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj11, "BenchFilePathObj11" ); +BENCH_FILEPATH_OBJECT( 12 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj12, "BenchFilePathObj12" ); +BENCH_FILEPATH_OBJECT( 13 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj13, "BenchFilePathObj13" ); +BENCH_FILEPATH_OBJECT( 14 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj14, "BenchFilePathObj14" ); +BENCH_FILEPATH_OBJECT( 15 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj15, "BenchFilePathObj15" ); +BENCH_FILEPATH_OBJECT( 16 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj16, "BenchFilePathObj16" ); +BENCH_FILEPATH_OBJECT( 17 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj17, "BenchFilePathObj17" ); +BENCH_FILEPATH_OBJECT( 18 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj18, "BenchFilePathObj18" ); +BENCH_FILEPATH_OBJECT( 19 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj19, "BenchFilePathObj19" ); +BENCH_FILEPATH_OBJECT( 20 ) CAF_PDM_SOURCE_INIT( BenchFilePathObj20, "BenchFilePathObj20" ); + +// clang-format on diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_mixed_fields.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_mixed_fields.cpp new file mode 100644 index 00000000000..b089c73a377 --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_mixed_fields.cpp @@ -0,0 +1,70 @@ +// Compile-time benchmark: PdmObjects with all field types combined +// This file represents the highest-signal benchmark: the full PDM field stack +// including basic, enum, container, and FilePath types in every object. + +#include "cafAppEnum.h" +#include "cafFilePath.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" + +#include +#include +#include + +// clang-format off + +#define BENCH_MIXED_OBJECT( N ) \ +enum class BenchMixedEnum##N { Alpha, Beta, Gamma, Delta }; \ +class BenchMixedObj##N : public caf::PdmObject \ +{ \ + CAF_PDM_HEADER_INIT; \ +public: \ + BenchMixedObj##N() \ + { \ + CAF_PDM_InitObject( "BenchMixedObj" #N ); \ + CAF_PDM_InitField( &m_intVal, "IntVal", 0, "Int" ); \ + CAF_PDM_InitField( &m_dblVal, "DblVal", 0.0, "Double" ); \ + CAF_PDM_InitField( &m_boolVal, "BoolVal", false, "Bool" ); \ + CAF_PDM_InitField( &m_strVal, "StrVal", QString(), "String" ); \ + CAF_PDM_InitField( &m_enumVal, "EnumVal", BenchMixedEnum##N::Alpha, "Enum" ); \ + CAF_PDM_InitFieldNoDefault( &m_vecDbl, "VecDbl", "Vector of doubles" ); \ + CAF_PDM_InitFieldNoDefault( &m_vecStr, "VecStr", "Vector of strings" ); \ + CAF_PDM_InitFieldNoDefault( &m_optDbl, "OptDbl", "Optional double" ); \ + CAF_PDM_InitFieldNoDefault( &m_fileA, "FileA", "File A" ); \ + auto pairInit = std::make_pair( false, 0.0 ); \ + CAF_PDM_InitField( &m_pairVal, "PairVal", pairInit, "Pair" ); \ + } \ + caf::PdmField m_intVal; \ + caf::PdmField m_dblVal; \ + caf::PdmField m_boolVal; \ + caf::PdmField m_strVal; \ + caf::PdmField> m_enumVal; \ + caf::PdmField> m_vecDbl; \ + caf::PdmField> m_vecStr; \ + caf::PdmField> m_optDbl; \ + caf::PdmField m_fileA; \ + caf::PdmField> m_pairVal; \ +}; + +BENCH_MIXED_OBJECT( 01 ) CAF_PDM_SOURCE_INIT( BenchMixedObj01, "BenchMixedObj01" ); +BENCH_MIXED_OBJECT( 02 ) CAF_PDM_SOURCE_INIT( BenchMixedObj02, "BenchMixedObj02" ); +BENCH_MIXED_OBJECT( 03 ) CAF_PDM_SOURCE_INIT( BenchMixedObj03, "BenchMixedObj03" ); +BENCH_MIXED_OBJECT( 04 ) CAF_PDM_SOURCE_INIT( BenchMixedObj04, "BenchMixedObj04" ); +BENCH_MIXED_OBJECT( 05 ) CAF_PDM_SOURCE_INIT( BenchMixedObj05, "BenchMixedObj05" ); +BENCH_MIXED_OBJECT( 06 ) CAF_PDM_SOURCE_INIT( BenchMixedObj06, "BenchMixedObj06" ); +BENCH_MIXED_OBJECT( 07 ) CAF_PDM_SOURCE_INIT( BenchMixedObj07, "BenchMixedObj07" ); +BENCH_MIXED_OBJECT( 08 ) CAF_PDM_SOURCE_INIT( BenchMixedObj08, "BenchMixedObj08" ); +BENCH_MIXED_OBJECT( 09 ) CAF_PDM_SOURCE_INIT( BenchMixedObj09, "BenchMixedObj09" ); +BENCH_MIXED_OBJECT( 10 ) CAF_PDM_SOURCE_INIT( BenchMixedObj10, "BenchMixedObj10" ); +BENCH_MIXED_OBJECT( 11 ) CAF_PDM_SOURCE_INIT( BenchMixedObj11, "BenchMixedObj11" ); +BENCH_MIXED_OBJECT( 12 ) CAF_PDM_SOURCE_INIT( BenchMixedObj12, "BenchMixedObj12" ); +BENCH_MIXED_OBJECT( 13 ) CAF_PDM_SOURCE_INIT( BenchMixedObj13, "BenchMixedObj13" ); +BENCH_MIXED_OBJECT( 14 ) CAF_PDM_SOURCE_INIT( BenchMixedObj14, "BenchMixedObj14" ); +BENCH_MIXED_OBJECT( 15 ) CAF_PDM_SOURCE_INIT( BenchMixedObj15, "BenchMixedObj15" ); +BENCH_MIXED_OBJECT( 16 ) CAF_PDM_SOURCE_INIT( BenchMixedObj16, "BenchMixedObj16" ); +BENCH_MIXED_OBJECT( 17 ) CAF_PDM_SOURCE_INIT( BenchMixedObj17, "BenchMixedObj17" ); +BENCH_MIXED_OBJECT( 18 ) CAF_PDM_SOURCE_INIT( BenchMixedObj18, "BenchMixedObj18" ); +BENCH_MIXED_OBJECT( 19 ) CAF_PDM_SOURCE_INIT( BenchMixedObj19, "BenchMixedObj19" ); +BENCH_MIXED_OBJECT( 20 ) CAF_PDM_SOURCE_INIT( BenchMixedObj20, "BenchMixedObj20" ); + +// clang-format on diff --git a/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/cafPdmBasicTest.cpp b/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/cafPdmBasicTest.cpp index d62ae6da3b6..0e89d1083af 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/cafPdmBasicTest.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/cafPdmBasicTest.cpp @@ -739,6 +739,10 @@ TEST( BaseTest, ReadWrite ) EXPECT_EQ( size_t( 1 ), simpleObjs.size() ); EXPECT_EQ( size_t( 0 ), simpleObjs[0]->m_numbers().size() ); } + + QFile::remove( fileName ); + QFile::remove( fileNameCopy ); + QFile::remove( "PdmTestFilWithError.xml" ); } //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/AppFwk/cafTests/cafTestApplication/CustomObjectEditor.cpp b/Fwk/AppFwk/cafTests/cafTestApplication/CustomObjectEditor.cpp index 85f1d07392a..fc5a5640a8d 100644 --- a/Fwk/AppFwk/cafTests/cafTestApplication/CustomObjectEditor.cpp +++ b/Fwk/AppFwk/cafTests/cafTestApplication/CustomObjectEditor.cpp @@ -36,6 +36,8 @@ #include "CustomObjectEditor.h" +#include "cafAssert.h" + #include "cafPdmUiGroup.h" #include "QMinimizePanel.h" diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiCheckBoxAndTextEditor.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiCheckBoxAndTextEditor.cpp index 10ffca68f9a..85583eb7bef 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiCheckBoxAndTextEditor.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiCheckBoxAndTextEditor.cpp @@ -84,7 +84,7 @@ void PdmUiCheckBoxAndTextEditor::configureAndUpdateUi( const QString& uiConfigNa bool isChecked = false; QString textString; - // A pair is converted into a list of QVariant in PdmValueFieldSpecialization> + // A pair is converted into a list of QVariant by pdmToVariant(const std::pair&) auto variantValue = uiField()->uiValue(); if ( variantValue.canConvert>() ) { @@ -155,7 +155,7 @@ void PdmUiCheckBoxAndTextEditor::slotSetValueToField() auto text = m_lineEdit->text(); auto pairValue = std::make_pair( isChecked, text ); - QVariant v = caf::PdmValueFieldSpecialization>::convert( pairValue ); + QVariant v = caf::pdmToVariant( pairValue ); this->setValueToField( v ); } diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiFormLayoutObjectEditor.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiFormLayoutObjectEditor.h index 3158f4705b5..78ad8a6ae33 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiFormLayoutObjectEditor.h +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiFormLayoutObjectEditor.h @@ -53,7 +53,9 @@ class QPushButton; namespace caf { +class PdmFieldHandle; class PdmUiFieldEditorHandle; +class PdmUiFieldHandle; class PdmUiGroup; class PdmUiLabel; class PdmUiButton; diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiLineEditor.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiLineEditor.h index 3731b8d12d7..f3f59b9d0c8 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiLineEditor.h +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiLineEditor.h @@ -36,6 +36,7 @@ #pragma once +#include "cafPdmOptionItemInfo.h" #include "cafPdmUiFieldLabelEditorHandle.h" #include diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiTableViewEditor.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiTableViewEditor.h index 61936cd9787..37e46c8708b 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiTableViewEditor.h +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiTableViewEditor.h @@ -50,6 +50,7 @@ class QLabel; namespace caf { +class PdmObjectHandle; class PdmUiCheckBoxDelegate; class PdmUiFieldEditorHandle; class PdmUiItem; diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeAttributes.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeAttributes.h index b5e6442be17..09a5916278a 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeAttributes.h +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeAttributes.h @@ -39,10 +39,12 @@ #include "cafPdmUiFieldEditorHandle.h" #include "cafSignal.h" +#include #include namespace caf { +class PdmObjectHandle; class PdmUiTreeViewItemAttribute : public PdmUiEditorAttribute { public: diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionQModel.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionQModel.h index 53fa931b705..d717fbdab00 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionQModel.h +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionQModel.h @@ -35,6 +35,7 @@ #pragma once +#include "cafPdmOptionItemInfo.h" #include "cafPdmUiFieldEditorHandle.h" #include "cafUiTreeManager.h" @@ -45,7 +46,6 @@ namespace caf { -class PdmOptionItemInfo; class PdmUiFieldHandle; //================================================================================================== diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiValueRangeEditor.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiValueRangeEditor.cpp index 8ce6abc2c4b..293ea7f56f3 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiValueRangeEditor.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiValueRangeEditor.cpp @@ -67,7 +67,7 @@ void PdmUiValueRangeEditor::configureAndUpdateUi( const QString& uiConfigName ) uiObject->editorAttribute( uiField()->fieldHandle(), uiConfigName, &m_attributes ); } - // A pair is represented as a list of QVariant in PdmValueFieldSpecialization> + // A pair is represented as a list of QVariant by pdmToVariant(const std::pair&) auto getTwoDoublesFromVariant = [this]() -> std::pair { double firstValue = 0.0; @@ -229,7 +229,7 @@ void PdmUiValueRangeEditor::writeValues( double valueMin, double valueMax ) { auto pairValue = std::make_pair( valueMin, valueMax ); - QVariant v = caf::PdmValueFieldSpecialization>::convert( pairValue ); + QVariant v = caf::pdmToVariant( pairValue ); setValueToField( v ); } diff --git a/Fwk/AppFwk/cafUserInterface/cafUserInterface_UnitTests/cafPdmUiCheckBoxAndTextEditorTest.cpp b/Fwk/AppFwk/cafUserInterface/cafUserInterface_UnitTests/cafPdmUiCheckBoxAndTextEditorTest.cpp index a8061e5673a..e88c3d5cae9 100644 --- a/Fwk/AppFwk/cafUserInterface/cafUserInterface_UnitTests/cafPdmUiCheckBoxAndTextEditorTest.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafUserInterface_UnitTests/cafPdmUiCheckBoxAndTextEditorTest.cpp @@ -1,8 +1,8 @@ #include "gtest/gtest.h" -#include "cafInternalPdmValueFieldSpecializations.h" #include "cafPdmField.h" +#include "cafPdmFieldTraits.h" #include "cafPdmObject.h" #include "cafPdmUiCheckBoxAndTextEditor.h" #include "cafPdmUiNumberFormat.h" @@ -72,7 +72,7 @@ TEST( PdmUiCheckBoxAndTextEditorTest, QVariantRoundTrip ) { auto original = std::make_pair( true, QString( "test value" ) ); - QVariant variant = PdmValueFieldSpecialization>::convert( original ); + QVariant variant = caf::pdmToVariant( original ); EXPECT_TRUE( variant.canConvert>() ); QList lst = variant.toList(); @@ -81,7 +81,7 @@ TEST( PdmUiCheckBoxAndTextEditorTest, QVariantRoundTrip ) EXPECT_EQ( lst[1].toString().toStdString(), "test value" ); std::pair restored; - PdmValueFieldSpecialization>::setFromVariant( variant, restored ); + caf::pdmFromVariant( variant, restored ); EXPECT_EQ( restored.first, original.first ); EXPECT_EQ( restored.second, original.second ); @@ -94,7 +94,7 @@ TEST( PdmUiCheckBoxAndTextEditorTest, QVariantUncheckedState ) { auto original = std::make_pair( false, QString( "disabled text" ) ); - QVariant variant = PdmValueFieldSpecialization>::convert( original ); + QVariant variant = caf::pdmToVariant( original ); QList lst = variant.toList(); EXPECT_EQ( lst[0].toBool(), false ); @@ -108,7 +108,7 @@ TEST( PdmUiCheckBoxAndTextEditorTest, NumberFormattingForDoubleValues ) { auto pair = std::make_pair( true, 1234.5678 ); - QVariant variant = PdmValueFieldSpecialization>::convert( pair ); + QVariant variant = caf::pdmToVariant( pair ); QList lst = variant.toList(); EXPECT_EQ( lst.size(), 2 ); @@ -131,10 +131,10 @@ TEST( PdmUiCheckBoxAndTextEditorTest, QVariantRoundTripDouble ) { auto original = std::make_pair( true, 42.5 ); - QVariant variant = PdmValueFieldSpecialization>::convert( original ); + QVariant variant = caf::pdmToVariant( original ); std::pair restored; - PdmValueFieldSpecialization>::setFromVariant( variant, restored ); + caf::pdmFromVariant( variant, restored ); EXPECT_EQ( restored.first, original.first ); EXPECT_DOUBLE_EQ( restored.second, original.second ); diff --git a/Fwk/CMakeLists.txt b/Fwk/CMakeLists.txt index 5a22abae640..92d24fc1fbf 100644 --- a/Fwk/CMakeLists.txt +++ b/Fwk/CMakeLists.txt @@ -58,6 +58,9 @@ add_subdirectory(AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXml_UnitTests) add_subdirectory(AppFwk/cafPdmScripting/cafPdmScripting_UnitTests) add_subdirectory(AppFwk/cafUserInterface/cafUserInterface_UnitTests) +# Compile-time benchmark (measures per-file compile cost of PDM field types) +add_subdirectory(AppFwk/cafProjectDataModel/cafPdm_CompileBench) + # Executables add_subdirectory(AppFwk/cafTests/cafTestApplication)