Refactors PdmUiFieldSpecialization implementation

* Simplifies PdmUiFieldSpecialization implementation.

Refactors the PdmUiFieldSpecialization implementation to reduce code duplication.

Introduces a base class `PdmUiFieldSpecializationForValueSpec` that delegates to `PdmValueFieldSpecialization`, avoiding boilerplate code for common types.

The primary template now inherits from the new base class, providing default behavior for types with custom `PdmValueFieldSpecialization`.

* Improve AppEnum subset handling to avoid key collisions

Refactored AppEnum to use a unique key combining owner class name and field keyword for enum subset storage, preventing collisions when different object types use the same field keyword. Updated setEnumSubset and enumSubset to accept PdmFieldHandle pointers. Added tests to verify correct and independent subset behavior across object types and handle edge cases.

* Refactor PdmValueFieldSpecialization with base helpers

Introduce base classes for default isEqual and QVariant conversion. Update specializations to inherit from these helpers, removing redundant code and centralizing default behaviors.
This commit is contained in:
Magne Sjaastad
2026-01-26 16:53:53 +01:00
committed by GitHub
parent ac594eb54e
commit caaf799229
11 changed files with 260 additions and 322 deletions
@@ -38,44 +38,7 @@
#include "cafPdmCoreMat3d.h"
#include "cafInternalPdmValueFieldSpecializations.h"
#include "cafPdmUiFieldSpecialization.h"
#include "cafPdmUiItem.h"
#include "cvfBase.h"
#include "cvfMatrix3.h"
namespace caf
{
template <>
class PdmUiFieldSpecialization<cvf::Mat3d>
{
public:
/// Convert the field value into a QVariant
static QVariant convert( const cvf::Mat3d& value )
{
return PdmValueFieldSpecialization<cvf::Mat3d>::convert( value );
}
/// Set the field value from a QVariant
static void setFromVariant( const QVariant& variantValue, cvf::Mat3d& value )
{
PdmValueFieldSpecialization<cvf::Mat3d>::setFromVariant( variantValue, value );
}
static bool isDataElementEqual( const QVariant& variantValue, const QVariant& variantValue2 )
{
return PdmValueFieldSpecialization<cvf::Mat3d>::isEqual( variantValue, variantValue2 );
}
/// Methods to get a list of options for a field, specialized for AppEnum
static QList<PdmOptionItemInfo> valueOptions( QString keyword, const cvf::Mat3d& )
{
return QList<PdmOptionItemInfo>();
}
/// Methods to retrieve the possible PdmObject pointed to by a field
static void childObjects( const PdmDataValueField<cvf::Mat3d>&, std::vector<PdmObjectHandle*>* ) {}
};
} // end namespace caf
@@ -39,47 +39,10 @@
#include "cvfBase.h"
#include "cvfColor3.h"
#include "cafInternalPdmValueFieldSpecializations.h"
#include "cafPdmUiFieldSpecialization.h"
#include "cafPdmUiItem.h"
#include "cafPdmCoreColor3f.h"
namespace caf
{
template <>
class PdmUiFieldSpecialization<cvf::Color3f>
{
public:
/// Convert the field value into a QVariant
static QVariant convert( const cvf::Color3f& value )
{
return PdmValueFieldSpecialization<cvf::Color3f>::convert( value );
}
/// Set the field value from a QVariant
static void setFromVariant( const QVariant& variantValue, cvf::Color3f& value )
{
PdmValueFieldSpecialization<cvf::Color3f>::setFromVariant( variantValue, value );
}
static bool isDataElementEqual( const QVariant& variantValue, const QVariant& variantValue2 )
{
return PdmValueFieldSpecialization<cvf::Color3f>::isEqual( variantValue, variantValue2 );
}
/// Methods to get a list of options for a field, specialized for AppEnum
static QList<PdmOptionItemInfo> valueOptions( QString keyword, const cvf::Color3f& )
{
return QList<PdmOptionItemInfo>();
}
/// Methods to retrieve the possible PdmObject pointed to by a field
static void childObjects( const PdmDataValueField<cvf::Color3f>&, std::vector<PdmObjectHandle*>* ) {}
};
} // end namespace caf
//--------------------------------------------------------------------------------------------------
// If the macro for registering the editor is put as the single statement
// in a cpp file, a dummy static class must be used to make sure the compile unit
-37
View File
@@ -38,44 +38,7 @@
#include "cafPdmCoreMat4d.h"
#include "cafInternalPdmValueFieldSpecializations.h"
#include "cafPdmUiFieldSpecialization.h"
#include "cafPdmUiItem.h"
#include "cvfBase.h"
#include "cvfMatrix4.h"
namespace caf
{
template <>
class PdmUiFieldSpecialization<cvf::Mat4d>
{
public:
/// Convert the field value into a QVariant
static QVariant convert( const cvf::Mat4d& value )
{
return PdmValueFieldSpecialization<cvf::Mat4d>::convert( value );
}
/// Set the field value from a QVariant
static void setFromVariant( const QVariant& variantValue, cvf::Mat4d& value )
{
PdmValueFieldSpecialization<cvf::Mat4d>::setFromVariant( variantValue, value );
}
static bool isDataElementEqual( const QVariant& variantValue, const QVariant& variantValue2 )
{
return PdmValueFieldSpecialization<cvf::Mat4d>::isEqual( variantValue, variantValue2 );
}
/// Methods to get a list of options for a field, specialized for AppEnum
static QList<PdmOptionItemInfo> valueOptions( QString keyword, const cvf::Mat4d& )
{
return QList<PdmOptionItemInfo>();
}
/// Methods to retrieve the possible PdmObject pointed to by a field
static void childObjects( const PdmDataValueField<cvf::Mat4d>&, std::vector<PdmObjectHandle*>* ) {}
};
} // end namespace caf
-37
View File
@@ -38,48 +38,11 @@
#include "cafPdmCoreVec3d.h"
#include "cafInternalPdmValueFieldSpecializations.h"
#include "cafPdmUiFieldSpecialization.h"
#include "cafPdmUiItem.h"
#include "cvfBase.h"
#include "cvfVector3.h"
namespace caf
{
template <>
class PdmUiFieldSpecialization<cvf::Vec3d>
{
public:
/// Convert the field value into a QVariant
static QVariant convert( const cvf::Vec3d& value )
{
return PdmValueFieldSpecialization<cvf::Vec3d>::convert( value );
}
/// Set the field value from a QVariant
static void setFromVariant( const QVariant& variantValue, cvf::Vec3d& value )
{
PdmValueFieldSpecialization<cvf::Vec3d>::setFromVariant( variantValue, value );
}
static bool isDataElementEqual( const QVariant& variantValue, const QVariant& variantValue2 )
{
return PdmValueFieldSpecialization<cvf::Vec3d>::isEqual( variantValue, variantValue2 );
}
/// Methods to get a list of options for a field, specialized for AppEnum
static QList<PdmOptionItemInfo> valueOptions( QString keyword, const cvf::Vec3d& )
{
return QList<PdmOptionItemInfo>();
}
/// Methods to retrieve the possible PdmObject pointed to by a field
static void childObjects( const PdmDataValueField<cvf::Vec3d>&, std::vector<PdmObjectHandle*>* ) {}
};
} // end namespace caf
//--------------------------------------------------------------------------------------------------
// If the macro for registering the editor is put as the single statement
// in a cpp file, a dummy static class must be used to make sure the compile unit
@@ -129,19 +129,34 @@ public:
{
}
static void setEnumSubset( caf::PdmFieldHandle* fieldKeyword, std::vector<T> subset )
static void setEnumSubset( caf::PdmFieldHandle* fieldHandle, std::vector<T> subset )
{
if ( !fieldKeyword ) return;
m_enumSubset[fieldKeyword->keyword()] = subset;
if ( !fieldHandle ) return;
QString key = createEnumSubsetKey( fieldHandle );
m_enumSubset[key] = subset;
}
static std::vector<T> enumSubset( QString fieldKeyword )
static std::vector<T> enumSubset( caf::PdmFieldHandle* fieldHandle )
{
auto it = m_enumSubset.find( fieldKeyword );
if ( !fieldHandle ) return {};
QString key = createEnumSubsetKey( fieldHandle );
auto it = m_enumSubset.find( key );
if ( it != m_enumSubset.end() ) return it->second;
return {};
}
private:
static QString createEnumSubsetKey( caf::PdmFieldHandle* fieldHandle )
{
if ( !fieldHandle ) return QString();
// Create a unique key by combining the owner class name with the field keyword
// This prevents collisions when different object types use the same field keyword
QString ownerClass = fieldHandle->ownerClass();
return ownerClass + "::" + fieldHandle->keyword();
}
public:
operator T() const { return m_value; }
T value() const { return m_value; }
@@ -201,7 +216,7 @@ private:
T m_value;
static std::map<QString, std::vector<T>> m_enumSubset;
static std::map<QString, std::vector<T>> m_enumSubset; // Key format: "ownerClass::fieldKeyword"
//==================================================================================================
/// A private class to handle the instance of the mapping vector.
@@ -12,6 +12,28 @@
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 <typename T>
struct PdmValueFieldSpecializationStdConversion
{
static QVariant convert( const T& value ) { return QVariant::fromValue( value ); }
static void setFromVariant( const QVariant& variantValue, T& value ) { value = variantValue.value<T>(); }
};
//==================================================================================================
/// A proxy class that implements the generic QVariant interface for a field
///
@@ -47,7 +69,7 @@ public:
/// Partial specialization for caf::AppEnum
//==================================================================================================
template <typename T>
class PdmValueFieldSpecialization<caf::AppEnum<T>>
class PdmValueFieldSpecialization<caf::AppEnum<T>> : public PdmValueFieldSpecializationDefaults
{
public:
static QVariant convert( const caf::AppEnum<T>& value )
@@ -61,11 +83,6 @@ public:
{
value = static_cast<T>( variantValue.toInt() );
}
static bool isEqual( const QVariant& variantValue, const QVariant& variantValue2 )
{
return variantValue == variantValue2;
}
};
//==================================================================================================
@@ -97,7 +114,7 @@ public:
/// Partial specialization for std::vector
//==================================================================================================
template <typename T>
class PdmValueFieldSpecialization<std::vector<T>>
class PdmValueFieldSpecialization<std::vector<T>> : public PdmValueFieldSpecializationDefaults
{
public:
static QVariant convert( const std::vector<T>& value )
@@ -127,18 +144,13 @@ public:
}
}
}
static bool isEqual( const QVariant& variantValue, const QVariant& variantValue2 )
{
return variantValue == variantValue2;
}
};
//==================================================================================================
/// Partial specialization for std::pair
//==================================================================================================
template <typename T, typename U>
class PdmValueFieldSpecialization<std::pair<T, U>>
class PdmValueFieldSpecialization<std::pair<T, U>> : public PdmValueFieldSpecializationDefaults
{
public:
static QVariant convert( const std::pair<T, U>& value )
@@ -168,11 +180,6 @@ public:
}
}
}
static bool isEqual( const QVariant& variantValue, const QVariant& variantValue2 )
{
return variantValue == variantValue2;
}
};
//==================================================================================================
@@ -199,13 +206,9 @@ public:
/// Partial specialization for float
//==================================================================================================
template <>
class PdmValueFieldSpecialization<float>
class PdmValueFieldSpecialization<float> : public PdmValueFieldSpecializationStdConversion<float>
{
public:
static QVariant convert( const float& value ) { return QVariant::fromValue( value ); }
static void setFromVariant( const QVariant& variantValue, float& value ) { value = variantValue.value<float>(); }
static bool isEqual( const QVariant& variantValue, const QVariant& variantValue2 )
{
// See PdmFieldWriter::writeFieldData for the precision used when writing float values
@@ -220,13 +223,9 @@ public:
/// Partial specialization for double
//==================================================================================================
template <>
class PdmValueFieldSpecialization<double>
class PdmValueFieldSpecialization<double> : public PdmValueFieldSpecializationStdConversion<double>
{
public:
static QVariant convert( const double& value ) { return QVariant::fromValue( value ); }
static void setFromVariant( const QVariant& variantValue, double& value ) { value = variantValue.value<double>(); }
static bool isEqual( const QVariant& variantValue, const QVariant& variantValue2 )
{
// See PdmFieldWriter::writeFieldData for the precision used when writing double values
@@ -27,6 +27,7 @@ set(PROJECT_FILES
cafPdmChildArrayFieldHandleTest.cpp
cafSignalTest.cpp
cafPdmLoggingTest.cpp
cafAppEnumTest.cpp
Child.cpp
Child.h
Parent.cpp
@@ -0,0 +1,144 @@
#include "gtest/gtest.h"
#include "cafAppEnum.h"
#include "cafPdmDataValueField.h"
#include "cafPdmObjectHandle.h"
// Define a test enum
enum class TestEnumType
{
VALUE_A,
VALUE_B,
VALUE_C,
VALUE_D,
VALUE_E
};
namespace caf
{
template <>
void AppEnum<TestEnumType>::setUp()
{
addItem( TestEnumType::VALUE_A, "VALUE_A", "Value A" );
addItem( TestEnumType::VALUE_B, "VALUE_B", "Value B" );
addItem( TestEnumType::VALUE_C, "VALUE_C", "Value C" );
addItem( TestEnumType::VALUE_D, "VALUE_D", "Value D" );
addItem( TestEnumType::VALUE_E, "VALUE_E", "Value E" );
setDefault( TestEnumType::VALUE_A );
}
} // namespace caf
// First test object with an enum field
class TestObject1 : public caf::PdmObjectHandle
{
public:
TestObject1()
{
this->addField( &m_enumField, "EnumField" );
m_enumField.setOwnerClass( "TestObject1" );
m_enumField = TestEnumType::VALUE_A;
}
caf::PdmDataValueField<caf::AppEnum<TestEnumType>> m_enumField;
};
// Second test object with an enum field using the same keyword
class TestObject2 : public caf::PdmObjectHandle
{
public:
TestObject2()
{
this->addField( &m_enumField, "EnumField" );
m_enumField.setOwnerClass( "TestObject2" );
m_enumField = TestEnumType::VALUE_B;
}
caf::PdmDataValueField<caf::AppEnum<TestEnumType>> m_enumField;
};
// Third test object to test uninitialized subset
class TestObject3 : public caf::PdmObjectHandle
{
public:
TestObject3()
{
this->addField( &m_enumField, "UniqueEnumField" );
m_enumField.setOwnerClass( "TestObject3" );
m_enumField = TestEnumType::VALUE_C;
}
caf::PdmDataValueField<caf::AppEnum<TestEnumType>> m_enumField;
};
//--------------------------------------------------------------------------------------------------
/// Test that two different objects can have the same field keyword with different enum subsets
//--------------------------------------------------------------------------------------------------
TEST( AppEnumTest, EnumSubsetNoCollision )
{
TestObject1 obj1;
TestObject2 obj2;
// Set different subsets for the same field keyword in different objects
std::vector<TestEnumType> subset1 = { TestEnumType::VALUE_A, TestEnumType::VALUE_B };
std::vector<TestEnumType> subset2 = { TestEnumType::VALUE_C, TestEnumType::VALUE_D, TestEnumType::VALUE_E };
caf::AppEnum<TestEnumType>::setEnumSubset( &obj1.m_enumField, subset1 );
caf::AppEnum<TestEnumType>::setEnumSubset( &obj2.m_enumField, subset2 );
// Retrieve the subsets
auto retrievedSubset1 = caf::AppEnum<TestEnumType>::enumSubset( &obj1.m_enumField );
auto retrievedSubset2 = caf::AppEnum<TestEnumType>::enumSubset( &obj2.m_enumField );
// Verify that the subsets are correct and independent
ASSERT_EQ( 2, retrievedSubset1.size() );
EXPECT_EQ( TestEnumType::VALUE_A, retrievedSubset1[0] );
EXPECT_EQ( TestEnumType::VALUE_B, retrievedSubset1[1] );
ASSERT_EQ( 3, retrievedSubset2.size() );
EXPECT_EQ( TestEnumType::VALUE_C, retrievedSubset2[0] );
EXPECT_EQ( TestEnumType::VALUE_D, retrievedSubset2[1] );
EXPECT_EQ( TestEnumType::VALUE_E, retrievedSubset2[2] );
}
//--------------------------------------------------------------------------------------------------
/// Test that multiple instances of the same class share the same subset
//--------------------------------------------------------------------------------------------------
TEST( AppEnumTest, EnumSubsetSameClass )
{
TestObject1 obj1a;
TestObject1 obj1b;
// Set subset for first instance
std::vector<TestEnumType> subset = { TestEnumType::VALUE_A, TestEnumType::VALUE_C };
caf::AppEnum<TestEnumType>::setEnumSubset( &obj1a.m_enumField, subset );
// Both instances should have the same subset since they have the same class name and field keyword
auto retrievedSubset1 = caf::AppEnum<TestEnumType>::enumSubset( &obj1a.m_enumField );
auto retrievedSubset2 = caf::AppEnum<TestEnumType>::enumSubset( &obj1b.m_enumField );
ASSERT_EQ( 2, retrievedSubset1.size() );
ASSERT_EQ( 2, retrievedSubset2.size() );
EXPECT_EQ( TestEnumType::VALUE_A, retrievedSubset1[0] );
EXPECT_EQ( TestEnumType::VALUE_C, retrievedSubset1[1] );
EXPECT_EQ( TestEnumType::VALUE_A, retrievedSubset2[0] );
EXPECT_EQ( TestEnumType::VALUE_C, retrievedSubset2[1] );
}
//--------------------------------------------------------------------------------------------------
/// Test that null field handle returns empty subset
//--------------------------------------------------------------------------------------------------
TEST( AppEnumTest, EnumSubsetNullHandle )
{
auto retrievedSubset = caf::AppEnum<TestEnumType>::enumSubset( nullptr );
EXPECT_TRUE( retrievedSubset.empty() );
}
//--------------------------------------------------------------------------------------------------
/// Test that requesting a subset that hasn't been set returns empty vector
//--------------------------------------------------------------------------------------------------
TEST( AppEnumTest, EnumSubsetNotSet )
{
TestObject3 obj;
auto retrievedSubset = caf::AppEnum<TestEnumType>::enumSubset( &obj.m_enumField );
EXPECT_TRUE( retrievedSubset.empty() );
}
@@ -13,6 +13,35 @@ class PdmPointer;
template <typename T>
class AppEnum;
//==================================================================================================
/// Helper base class for types that delegate all operations to PdmValueFieldSpecialization.
/// Inherit from this to avoid repeating the delegation boilerplate.
//==================================================================================================
template <typename T>
struct PdmUiFieldSpecializationForValueSpec : public PdmUiFieldSpecializationDefaults
{
static QVariant convert( const T& value ) { return PdmValueFieldSpecialization<T>::convert( value ); }
static void setFromVariant( const QVariant& variantValue, T& value )
{
PdmValueFieldSpecialization<T>::setFromVariant( variantValue, value );
}
static bool isDataElementEqual( const QVariant& variantValue, const QVariant& variantValue2 )
{
return PdmValueFieldSpecialization<T>::isEqual( variantValue, variantValue2 );
}
};
//==================================================================================================
/// Primary template - delegates to PdmValueFieldSpecialization<T>.
/// Types with custom PdmValueFieldSpecialization will automatically get correct behavior.
//==================================================================================================
template <typename T>
class PdmUiFieldSpecialization : public PdmUiFieldSpecializationForValueSpec<T>
{
};
//==================================================================================================
/// Partial specialization for PdmField< PdmPointer<T> >
///
@@ -24,7 +53,7 @@ class AppEnum;
//==================================================================================================
template <typename T>
class PdmUiFieldSpecialization<PdmPointer<T>>
class PdmUiFieldSpecialization<PdmPointer<T>> : public PdmUiFieldSpecializationDefaults
{
public:
static QVariant convert( const PdmPointer<T>& value )
@@ -41,11 +70,6 @@ public:
{
return variantValue.value<PdmPointer<PdmObjectHandle>>() == variantValue2.value<PdmPointer<PdmObjectHandle>>();
}
static QList<PdmOptionItemInfo> valueOptions( QString keyword, const PdmPointer<T>& )
{
return QList<PdmOptionItemInfo>();
}
};
//==================================================================================================
@@ -53,7 +77,7 @@ public:
//==================================================================================================
template <typename T>
class PdmUiFieldSpecialization<std::list<T>>
class PdmUiFieldSpecialization<std::list<T>> : public PdmUiFieldSpecializationDefaults
{
public:
static QVariant convert( const std::list<T>& value )
@@ -85,13 +109,6 @@ public:
{
return PdmValueFieldSpecialization<T>::isEqual( variantValue, variantValue2 );
}
static QList<PdmOptionItemInfo> valueOptions( QString keyword, const std::list<T>& )
{
return QList<PdmOptionItemInfo>();
}
static void childObjects( const PdmDataValueField<std::list<T>>&, std::vector<PdmObjectHandle*>* ) {}
};
//==================================================================================================
@@ -99,7 +116,7 @@ public:
//==================================================================================================
template <typename T>
class PdmUiFieldSpecialization<std::vector<T>>
class PdmUiFieldSpecialization<std::vector<T>> : public PdmUiFieldSpecializationDefaults
{
public:
static QVariant convert( const std::vector<T>& value )
@@ -116,22 +133,13 @@ public:
{
return PdmValueFieldSpecialization<T>::isEqual( variantValue, variantValue2 );
}
static QList<PdmOptionItemInfo> valueOptions( QString keyword, const std::vector<T>& )
{
return QList<PdmOptionItemInfo>();
}
static void childObjects( const PdmDataValueField<std::vector<T>>& field, std::vector<PdmObjectHandle*>* objects )
{
}
};
//==================================================================================================
/// Partial specialization for PdmField< caf::AppEnum<T> >
//==================================================================================================
template <typename T>
class PdmUiFieldSpecialization<caf::AppEnum<T>>
class PdmUiFieldSpecialization<caf::AppEnum<T>> : public PdmUiFieldSpecializationDefaults
{
public:
static QVariant convert( const caf::AppEnum<T>& value )
@@ -147,17 +155,12 @@ public:
value = static_cast<T>( variantValue.toInt() );
}
static bool isDataElementEqual( const QVariant& variantValue, const QVariant& variantValue2 )
{
return variantValue == variantValue2;
}
static QList<PdmOptionItemInfo> valueOptions( QString keyword, const caf::AppEnum<T>& appEnum )
static QList<PdmOptionItemInfo> valueOptions( PdmFieldHandle* fieldHandle, const caf::AppEnum<T>& appEnum )
{
QList<PdmOptionItemInfo> optionList;
// If a subset of the enum is defined, use that subset
auto enumValues = caf::AppEnum<T>::enumSubset( keyword );
auto enumValues = caf::AppEnum<T>::enumSubset( fieldHandle );
if ( enumValues.empty() )
{
// If no subset is defined, use all values
@@ -173,17 +176,13 @@ public:
return optionList;
}
static void childObjects( const PdmDataValueField<caf::AppEnum<T>>& field, std::vector<PdmObjectHandle*>* objects )
{
}
};
//==================================================================================================
/// Partial specialization for PdmField<std::pair<T, U>>>
//==================================================================================================
template <typename T, typename U>
class PdmUiFieldSpecialization<std::pair<T, U>>
class PdmUiFieldSpecialization<std::pair<T, U>> : public PdmUiFieldSpecializationDefaults
{
public:
static QVariant convert( const std::pair<T, U>& value )
@@ -195,29 +194,13 @@ public:
{
PdmValueFieldSpecialization<std::pair<T, U>>::setFromVariant( variantValue, value );
}
static bool isDataElementEqual( const QVariant& variantValue, const QVariant& variantValue2 )
{
return variantValue == variantValue2;
}
static QList<PdmOptionItemInfo> valueOptions( QString keyword, const std::pair<T, U>& )
{
QList<PdmOptionItemInfo> optionList;
return optionList;
}
static void childObjects( const PdmDataValueField<std::pair<T, U>>& field, std::vector<PdmObjectHandle*>* objects )
{
}
};
//==================================================================================================
/// Partial specialization for PdmField<std::optional<T>>>
//==================================================================================================
template <typename T>
class PdmUiFieldSpecialization<std::optional<T>>
class PdmUiFieldSpecialization<std::optional<T>> : public PdmUiFieldSpecializationDefaults
{
public:
/// Convert the field value into a QVariant
@@ -247,59 +230,6 @@ public:
PdmValueFieldSpecialization<T>::setFromVariant( variantValue, valueOfType );
value = valueOfType;
}
static bool isDataElementEqual( const QVariant& variantValue, const QVariant& variantValue2 )
{
return variantValue == variantValue2;
}
/// Methods to get a list of options for a field, specialized for std::optional<T>
static QList<PdmOptionItemInfo> valueOptions( QString keyword, const std::optional<T>& )
{
QList<PdmOptionItemInfo> optionList;
return optionList;
}
/// Methods to retrieve the possible PdmObject pointed to by a field
static void childObjects( const PdmDataValueField<std::optional<T>>& field, std::vector<PdmObjectHandle*>* objects )
{
}
};
//==================================================================================================
/// Partial specialization for FilePath
//==================================================================================================
template <>
class PdmUiFieldSpecialization<caf::FilePath>
{
public:
/// Convert the field value into a QVariant
static QVariant convert( const caf::FilePath& value )
{
return PdmValueFieldSpecialization<caf::FilePath>::convert( value );
}
/// Set the field value from a QVariant
static void setFromVariant( const QVariant& variantValue, caf::FilePath& value )
{
return PdmValueFieldSpecialization<caf::FilePath>::setFromVariant( variantValue, value );
}
static bool isDataElementEqual( const QVariant& variantValue, const QVariant& variantValue2 )
{
return PdmValueFieldSpecialization<caf::FilePath>::isEqual( variantValue, variantValue2 );
}
/// Methods to get a list of options for a field, specialized for caf::FilePath
static QList<PdmOptionItemInfo> valueOptions( QString keyword, const caf::FilePath& )
{
return QList<PdmOptionItemInfo>();
}
/// Methods to retrieve the possible PdmObject pointed to by a field
static void childObjects( const PdmDataValueField<caf::FilePath>& field, std::vector<PdmObjectHandle*>* objects ) {}
};
} // End namespace caf
@@ -198,9 +198,8 @@ QList<PdmOptionItemInfo> PdmFieldUiCap<FieldType>::valueOptions() const
if ( m_optionEntryCache.empty() )
{
auto keyword = m_field->keyword();
m_optionEntryCache =
PdmUiFieldSpecialization<typename FieldType::FieldDataType>::valueOptions( keyword, m_field->value() );
PdmUiFieldSpecialization<typename FieldType::FieldDataType>::valueOptions( m_field, m_field->value() );
}
if ( !m_optionEntryCache.empty() && isAutoAddingOptionFromValue() )
@@ -11,6 +11,30 @@ template <typename T>
class PdmDataValueField;
class PdmOptionItemInfo;
class PdmObjectHandle;
class PdmFieldHandle;
//==================================================================================================
/// Base class providing default implementations for PdmUiFieldSpecialization methods.
/// Specializations can inherit from this to avoid repeating empty/simple implementations.
//==================================================================================================
struct PdmUiFieldSpecializationDefaults
{
static bool isDataElementEqual( const QVariant& variantValue, const QVariant& variantValue2 )
{
return variantValue == variantValue2;
}
template <typename T>
static QList<PdmOptionItemInfo> valueOptions( PdmFieldHandle*, const T& )
{
return QList<PdmOptionItemInfo>();
}
template <typename T>
static void childObjects( const PdmDataValueField<T>&, std::vector<PdmObjectHandle*>* )
{
}
};
//==================================================================================================
/// A proxy class that implements the Gui interface of fields
@@ -21,40 +45,14 @@ class PdmObjectHandle;
///
/// 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<T>, so types with custom
/// PdmValueFieldSpecialization will automatically get the correct behavior without needing
/// an explicit PdmUiFieldSpecialization.
//==================================================================================================
template <typename T>
class PdmUiFieldSpecialization
{
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<T>(); }
/// 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
/// This is needed for the lookup regarding OptionValues
static bool isDataElementEqual( const QVariant& variantValue, const QVariant& variantValue2 )
{
if ( variantValue.typeId() > QMetaType::User )
{
return ( variantValue.value<T>() == variantValue2.value<T>() );
}
else
{
return variantValue == variantValue2;
}
}
/// Methods to get a list of options for a field
static QList<PdmOptionItemInfo> valueOptions( QString keyword, const T& ) { return QList<PdmOptionItemInfo>(); }
/// Methods to retrieve the possible PdmObject pointed to by a field
static void childObjects( const PdmDataValueField<T>&, std::vector<PdmObjectHandle*>* ) {}
};
class PdmUiFieldSpecialization; // Forward declaration, defined in cafInternalPdmFieldTypeSpecializations.h
} // End of namespace caf
#include "cafInternalPdmFieldTypeSpecializations.h"