Fix ADL lookup for cvf pdmToVariant/pdmFromVariant overloads

Move pdmToVariant/pdmFromVariant overloads for cvf::Color3f, Vec3d, Mat4d, and
Mat3d from namespace caf to namespace cvf. Templates in
cafInternalPdmFieldTypeSpecializations.h use "using caf::pdmToVariant" followed
by an unqualified call, so ADL searches the argument's namespace (cvf). With the
overloads only in caf, the default template was selected, causing cvf::Color3f to
be stored raw in a QVariant instead of as QColor — breaking color field editing
and producing QVariant::save warnings.

All call sites now use the unqualified "using caf::pdmXxx; pdmXxx(value)" pattern
so ADL finds the correct overload without depending on cvf:: as a visible prefix.
Add AdlVariantTest to cafPdmCoreColor3fTest.cpp that exercises this exact pattern.

Adds caf::toVariant<T> and caf::fromVariant<T> to cafPdmFieldTraits.h as
thin wrappers that encapsulate the ADL two-step internally. Client code can
now call caf::toVariant(x) directly instead of requiring a using-declaration
at every call site.
This commit is contained in:
Magne Sjaastad authored and GitHub committed 2026-04-08 23:12:49 +02:00
1 parent 700549fb3b
commit e8223485b1
13 files changed
+107 -38

No files matched your search

@@ -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::pdmFromVariant( eyeVariant, eye );
caf::pdmFromVariant( vrpVariant, vrp );
caf::pdmFromVariant( upVariant, up );
caf::fromVariant( eyeVariant, eye );
caf::fromVariant( vrpVariant, vrp );
caf::fromVariant( upVariant, up );
}
@@ -104,14 +104,9 @@ void RicStoreUserDefinedCameraFeature::onActionTriggered( bool isChecked )
camera->toLookAt( &eye, &vrp, &up );
QVariant eyeVariant = caf::pdmToVariant( eye );
settings.setValue( RicStoreUserDefinedCameraFeature::eyeName(), eyeVariant );
QVariant vrpVariant = caf::pdmToVariant( vrp );
settings.setValue( RicStoreUserDefinedCameraFeature::viewReferencePointName(), vrpVariant );
QVariant upVariant = caf::pdmToVariant( up );
settings.setValue( RicStoreUserDefinedCameraFeature::upName(), upVariant );
settings.setValue( RicStoreUserDefinedCameraFeature::eyeName(), caf::toVariant( eye ) );
settings.setValue( RicStoreUserDefinedCameraFeature::viewReferencePointName(), caf::toVariant( vrp ) );
settings.setValue( RicStoreUserDefinedCameraFeature::upName(), caf::toVariant( up ) );
RiuMainWindow::instance()->refreshViewActions();
}
@@ -177,7 +177,7 @@ void RicTextAnnotation3dEditor::updatePoint( caf::PdmUiFieldHandle* uiField, con
cvf::Vec3d domainPos = dispXf->transformToDomainCoord( newPos );
domainPos.z() = -domainPos.z();
QVariant originVariant = caf::pdmToVariant( domainPos );
QVariant originVariant = caf::toVariant( domainPos );
caf::PdmUiCommandSystemProxy::instance()->setUiValueToField( uiField, originVariant );
}
@@ -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::pdmToVariant( domainOrigin );
QVariant originVariant = caf::toVariant( domainOrigin );
caf::PdmUiCommandSystemProxy::instance()->setUiValueToField( target->targetPointUiCapability(), originVariant );
}
@@ -520,7 +520,7 @@ void RimWellPathGeometryDef::fieldChangedByUi( const caf::PdmFieldHandle* change
linkedDefs.end() );
cvf::Vec3d oldPos;
caf::pdmFromVariant( oldValue, oldPos );
caf::fromVariant( oldValue, oldPos );
auto delta = m_referencePointUtmXyd() - oldPos;
+10 -3
View File
@@ -44,22 +44,29 @@
#include <QColor>
namespace caf
// pdmToVariant/pdmFromVariant in namespace cvf so ADL finds them when called via caf::toVariant/
// caf::fromVariant — ADL searches the argument's namespace (cvf) in addition to caf.
namespace cvf
{
inline QVariant pdmToVariant( const cvf::Color3f& value )
inline QVariant pdmToVariant( const Color3f& value )
{
QColor col;
col.setRgbF( value.r(), value.g(), value.b() );
return col;
}
inline void pdmFromVariant( const QVariant& v, cvf::Color3f& out )
inline void pdmFromVariant( const QVariant& v, Color3f& out )
{
QColor col = v.value<QColor>();
out.set( col.redF(), col.greenF(), col.blueF() );
}
} // end namespace cvf
namespace caf
{
template <>
struct PdmVariantEqualImpl<cvf::Color3f>
{
+10 -3
View File
@@ -45,10 +45,12 @@
#include <QTextStream>
namespace caf
// pdmToVariant/pdmFromVariant in namespace cvf so ADL finds them when called via caf::toVariant/
// caf::fromVariant — ADL searches the argument's namespace (cvf) in addition to caf.
namespace cvf
{
inline QVariant pdmToVariant( const cvf::Mat4d& value )
inline QVariant pdmToVariant( const Mat4d& value )
{
QString str;
QTextStream textStream( &str );
@@ -56,13 +58,18 @@ inline QVariant pdmToVariant( const cvf::Mat4d& value )
return QVariant( str );
}
inline void pdmFromVariant( const QVariant& v, cvf::Mat4d& out )
inline void pdmFromVariant( const QVariant& v, Mat4d& out )
{
QString str = v.toString();
QTextStream textStream( &str );
textStream >> out;
}
} // end namespace cvf
namespace caf
{
template <>
struct PdmVariantEqualImpl<cvf::Mat4d>
{
+10 -3
View File
@@ -47,10 +47,12 @@
Q_DECLARE_METATYPE( cvf::Vec3d );
namespace caf
// pdmToVariant/pdmFromVariant in namespace cvf so ADL finds them when called via caf::toVariant/
// caf::fromVariant — ADL searches the argument's namespace (cvf) in addition to caf.
namespace cvf
{
inline QVariant pdmToVariant( const cvf::Vec3d& value )
inline QVariant pdmToVariant( const Vec3d& value )
{
QString str;
QTextStream textStream( &str );
@@ -58,13 +60,18 @@ inline QVariant pdmToVariant( const cvf::Vec3d& value )
return QVariant( str );
}
inline void pdmFromVariant( const QVariant& v, cvf::Vec3d& out )
inline void pdmFromVariant( const QVariant& v, Vec3d& out )
{
QString str = v.toString();
QTextStream textStream( &str );
textStream >> out;
}
} // end namespace cvf
namespace caf
{
template <>
struct PdmVariantEqualImpl<cvf::Vec3d>
{
@@ -1,7 +1,11 @@
#include "cafPdmCoreColor3f.h"
#include "cafPdmFieldTraits.h"
#include "gtest/gtest.h"
#include <QColor>
TEST( SerializeTest, PdmCoreColor3f )
{
float r = 0.4f;
@@ -33,10 +37,10 @@ TEST( VariantTest, PdmCoreColor3f )
float b = 0.18f;
cvf::Color3f myColor( r, g, b );
QVariant myVariant = caf::pdmToVariant( myColor );
QVariant myVariant = caf::toVariant( myColor );
cvf::Color3f decoded;
caf::pdmFromVariant( myVariant, decoded );
caf::fromVariant( myVariant, decoded );
EXPECT_FLOAT_EQ( myColor.r(), decoded.r() );
EXPECT_FLOAT_EQ( myColor.g(), decoded.g() );
@@ -49,14 +53,33 @@ TEST( VariantEqualTest, PdmCoreColor3f )
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 );
QVariant va = caf::toVariant( a );
QVariant vb = caf::toVariant( b );
QVariant vc = caf::toVariant( c );
EXPECT_TRUE( caf::pdmVariantEqual<cvf::Color3f>( va, vb ) );
EXPECT_FALSE( caf::pdmVariantEqual<cvf::Color3f>( va, vc ) );
}
// Verifies that caf::toVariant dispatches to the cvf::Color3f overload via ADL,
// producing a QColor variant rather than a raw cvf::Color3f.
TEST( AdlVariantTest, PdmCoreColor3f )
{
cvf::Color3f original( 0.4f, 0.2f, 0.18f );
QVariant variant = caf::toVariant( original );
// The variant must hold a QColor, not a raw cvf::Color3f
EXPECT_TRUE( variant.canConvert<QColor>() );
cvf::Color3f decoded;
caf::fromVariant( variant, decoded );
EXPECT_FLOAT_EQ( original.r(), decoded.r() );
EXPECT_FLOAT_EQ( original.g(), decoded.g() );
EXPECT_NEAR( original.b(), decoded.b(), 0.01 );
}
TEST( SerializeSeveralTest, PdmCoreColor3f )
{
float r = 0.4f;
@@ -53,10 +53,10 @@ TEST( VariantTest, PdmCoreMat4d )
{
cvf::Mat4d myMatrix = createMatrix();
QVariant myVariant = caf::pdmToVariant( myMatrix );
QVariant myVariant = caf::toVariant( myMatrix );
cvf::Mat4d decoded;
caf::pdmFromVariant( myVariant, decoded );
caf::fromVariant( myVariant, decoded );
EXPECT_TRUE( decoded.equals( myMatrix ) );
}
@@ -37,10 +37,10 @@ TEST( VariantTest, PdmCoreVec3d )
cvf::Vec3d myVector( a, b, c );
QVariant myVariant = caf::pdmToVariant( myVector );
QVariant myVariant = caf::toVariant( myVector );
cvf::Vec3d decoded;
caf::pdmFromVariant( myVariant, decoded );
caf::fromVariant( myVariant, decoded );
EXPECT_TRUE( decoded.equals( myVector ) );
}
@@ -51,9 +51,9 @@ TEST( VariantEqualTest, PdmCoreVec3d )
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 );
QVariant va = caf::toVariant( a );
QVariant vb = caf::toVariant( b );
QVariant vc = caf::toVariant( c );
EXPECT_TRUE( caf::pdmVariantEqual<cvf::Vec3d>( va, vb ) );
EXPECT_FALSE( caf::pdmVariantEqual<cvf::Vec3d>( va, vc ) );
@@ -45,10 +45,12 @@
#include <QTextStream>
namespace caf
// pdmToVariant/pdmFromVariant in namespace cvf so ADL finds them when called via caf::toVariant/
// caf::fromVariant — ADL searches the argument's namespace (cvf) in addition to caf.
namespace cvf
{
inline QVariant pdmToVariant( const cvf::Mat3d& value )
inline QVariant pdmToVariant( const Mat3d& value )
{
QString str;
QTextStream textStream( &str );
@@ -56,13 +58,18 @@ inline QVariant pdmToVariant( const cvf::Mat3d& value )
return QVariant( str );
}
inline void pdmFromVariant( const QVariant& v, cvf::Mat3d& out )
inline void pdmFromVariant( const QVariant& v, Mat3d& out )
{
QString str = v.toString();
QTextStream textStream( &str );
textStream >> out;
}
} // end namespace cvf
namespace caf
{
template <>
struct PdmVariantEqualImpl<cvf::Mat3d>
{
@@ -120,6 +120,29 @@ void pdmFromVariant( const QVariant& v, std::optional<T>& out )
out = underlying;
}
//==================================================================================================
/// toVariant / fromVariant — public API wrappers
///
/// Simple qualified-call entry points that encapsulate the ADL two-step internally.
/// Prefer these over calling pdmToVariant/pdmFromVariant with a using-declaration at the call site.
/// Custom types are still extended by adding pdmToVariant/pdmFromVariant overloads in the type's
/// own namespace; these wrappers just hide that detail from callers.
//==================================================================================================
template <typename T>
QVariant toVariant( const T& value )
{
using caf::pdmToVariant;
return pdmToVariant( value );
}
template <typename T>
void fromVariant( const QVariant& v, T& out )
{
using caf::pdmFromVariant;
pdmFromVariant( v, out );
}
//==================================================================================================
/// PdmVariantEqualImpl<T>
///