ResInsight/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafInternalPdmValueFieldSpecializations.h
Magne Sjaastad 13532b0fe4 Add partial specialization for float and double
In PdmFieldWriter::writeFieldData, the numeric values are converted to string with a selected precision. isEqual() is used when comparing values for field editors in PdmFieldUiCap<FieldType>::valueOptions()
2024-06-12 09:35:28 +02:00

241 lines
8.8 KiB
C++

#pragma once
#include "cafAppEnum.h"
#include "cafFilePath.h"
#include "cafPdmPointer.h"
#include <assert.h>
#include <type_traits>
#include <vector>
#include <QVariant>
namespace caf
{
//==================================================================================================
/// 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 <typename T>
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<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
/// Using the == between the real types is more safe.
static bool isEqual( const QVariant& variantValue, const QVariant& variantValue2 )
{
return variantValue.value<T>() == variantValue2.value<T>();
}
};
//==================================================================================================
/// Partial specialization for caf::AppEnum
//==================================================================================================
template <typename T>
class PdmValueFieldSpecialization<caf::AppEnum<T>>
{
public:
static QVariant convert( const caf::AppEnum<T>& 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<int>( enumValue ) );
}
static void setFromVariant( const QVariant& variantValue, caf::AppEnum<T>& value )
{
value = static_cast<T>( variantValue.toInt() );
}
static bool isEqual( const QVariant& variantValue, const QVariant& variantValue2 )
{
return variantValue == variantValue2;
}
};
//==================================================================================================
/// Partial specialization for caf::PdmPointer<T>
/// Used internally to avoid havning to declare everything Q_DECLARE_METATYPE()
/// User must use PdmPtrField or PdmChildField
//==================================================================================================
template <typename T>
class PdmValueFieldSpecialization<PdmPointer<T>>
{
public:
static QVariant convert( const PdmPointer<T>& value )
{
return QVariant::fromValue( PdmPointer<PdmObjectHandle>( value.rawPtr() ) );
}
static void setFromVariant( const QVariant& variantValue, caf::PdmPointer<T>& value )
{
value.setRawPtr( variantValue.value<PdmPointer<PdmObjectHandle>>().rawPtr() );
}
static bool isEqual( const QVariant& variantValue, const QVariant& variantValue2 )
{
return variantValue.value<PdmPointer<PdmObjectHandle>>() == variantValue2.value<PdmPointer<PdmObjectHandle>>();
}
};
//==================================================================================================
/// Partial specialization for std::vector
//==================================================================================================
template <typename T>
class PdmValueFieldSpecialization<std::vector<T>>
{
public:
static QVariant convert( const std::vector<T>& value )
{
QList<QVariant> returnList;
typename std::vector<T>::const_iterator it;
for ( it = value.begin(); it != value.end(); ++it )
{
returnList.push_back( PdmValueFieldSpecialization<T>::convert( *it ) );
}
return returnList;
}
static void setFromVariant( const QVariant& variantValue, std::vector<T>& value )
{
if ( variantValue.canConvert<QList<QVariant>>() )
{
value.clear();
QList<QVariant> lst = variantValue.toList();
for ( int i = 0; i < lst.size(); ++i )
{
T val;
PdmValueFieldSpecialization<T>::setFromVariant( lst[i], val );
value.push_back( val );
}
}
}
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>>
{
public:
static QVariant convert( const std::pair<T, U>& value )
{
QList<QVariant> returnList;
returnList.push_back( PdmValueFieldSpecialization<T>::convert( value.first ) );
returnList.push_back( PdmValueFieldSpecialization<U>::convert( value.second ) );
return returnList;
}
static void setFromVariant( const QVariant& variantValue, std::pair<T, U>& value )
{
if ( variantValue.canConvert<QList<QVariant>>() )
{
QList<QVariant> lst = variantValue.toList();
if ( lst.size() == 2 )
{
T first;
PdmValueFieldSpecialization<T>::setFromVariant( lst[0], first );
U second;
PdmValueFieldSpecialization<U>::setFromVariant( lst[1], second );
value = std::make_pair( first, second );
}
}
}
static bool isEqual( const QVariant& variantValue, const QVariant& variantValue2 )
{
return variantValue == variantValue2;
}
};
//==================================================================================================
/// Partial specialization for caf::FilePath
//==================================================================================================
template <>
class PdmValueFieldSpecialization<FilePath>
{
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<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
// This function is used when comparing values for field editors in PdmFieldUiCap<FieldType>::valueOptions()
const float epsilon = 1e-6f;
return qAbs( variantValue.value<float>() - variantValue2.value<float>() ) < epsilon;
}
};
//==================================================================================================
/// Partial specialization for double
//==================================================================================================
template <>
class PdmValueFieldSpecialization<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
// This function is used when comparing values for field editors in PdmFieldUiCap<FieldType>::valueOptions()
const double epsilon = 1e-8;
return qAbs( variantValue.value<double>() - variantValue2.value<double>() ) < epsilon;
}
};
} // End of namespace caf