mirror of
https://github.com/OPM/ResInsight.git
synced 2026-10-26 07:00:17 -05:00
Introduce cafPdmFieldTraits.h with ADL-based pdmToVariant/pdmFromVariant/pdmVariantEqual as a replacement for PdmValueFieldSpecialization. Migrate all types (AppEnum, FilePath, PdmPointer, cvf types) and all call sites (PdmDataValueField, PdmProxyValueField, UI framework, ApplicationLibCode). Delete cafInternalPdmValueFieldSpecializations.h. Add cafPdmFieldTraits unit tests and fix std::optional support.
342 lines
12 KiB
C++
342 lines
12 KiB
C++
//##################################################################################################
|
|
//
|
|
// Custom Visualization Core library
|
|
// Copyright (C) 2011-2013 Ceetron AS
|
|
//
|
|
// This library may be used under the terms of either the GNU General Public License or
|
|
// the GNU Lesser General Public License as follows:
|
|
//
|
|
// GNU General Public License Usage
|
|
// This library is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This library is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
|
//
|
|
// See the GNU General Public License at <<http://www.gnu.org/licenses/gpl.html>>
|
|
// for more details.
|
|
//
|
|
// GNU Lesser General Public License Usage
|
|
// This library is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
// the Free Software Foundation; either version 2.1 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This library is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
|
//
|
|
// See the GNU Lesser General Public License at <<http://www.gnu.org/licenses/lgpl-2.1.html>>
|
|
// for more details.
|
|
//
|
|
//##################################################################################################
|
|
#ifndef CAF_IS_DEFINING_PDM_FIELD
|
|
#pragma once
|
|
#endif
|
|
|
|
#include "cafPdmValueField.h"
|
|
|
|
#include "cafAssert.h"
|
|
#include "cafPdmFieldTraits.h"
|
|
#include "cafPdmUiFieldHandleInterface.h"
|
|
|
|
#include <QVariant>
|
|
|
|
#include <optional>
|
|
#include <type_traits>
|
|
#include <typeinfo>
|
|
#include <vector>
|
|
|
|
namespace caf
|
|
{
|
|
class PdmObjectHandle;
|
|
|
|
//==================================================================================================
|
|
/// Field class encapsulating data with input and output of this data to/from a QXmlStream
|
|
/// read/write-FieldData is supposed to be specialized for types needing specialization
|
|
//==================================================================================================
|
|
|
|
template <typename DataType>
|
|
class PdmDataValueField : public PdmValueField
|
|
{
|
|
public:
|
|
// Type traits magic to check if a template argument is a vector
|
|
template <typename T>
|
|
struct is_vector : public std::false_type
|
|
{
|
|
};
|
|
template <typename T, typename A>
|
|
struct is_vector<std::vector<T, A>> : public std::true_type
|
|
{
|
|
};
|
|
|
|
// Type trait to detect std::pair<bool, ArithmeticType>
|
|
template <typename T>
|
|
struct is_bool_arithmetic_pair : public std::false_type
|
|
{
|
|
};
|
|
template <typename T>
|
|
struct is_bool_arithmetic_pair<std::pair<bool, T>> : public std::integral_constant<bool, std::is_arithmetic<T>::value>
|
|
{
|
|
};
|
|
|
|
typedef DataType FieldDataType;
|
|
PdmDataValueField()
|
|
: m_fieldValue( DataType() )
|
|
, m_defaultFieldValue( DataType() )
|
|
{
|
|
}
|
|
PdmDataValueField( const PdmDataValueField& other ) { m_fieldValue = other.m_fieldValue; }
|
|
explicit PdmDataValueField( const DataType& fieldValue ) { m_fieldValue = fieldValue; }
|
|
~PdmDataValueField() override {}
|
|
|
|
// Assignment
|
|
|
|
PdmDataValueField& operator=( const PdmDataValueField& other )
|
|
{
|
|
CAF_ASSERT( isInitializedByInitFieldMacro() );
|
|
m_fieldValue = other.m_fieldValue;
|
|
return *this;
|
|
}
|
|
PdmDataValueField& operator=( const DataType& fieldValue )
|
|
{
|
|
CAF_ASSERT( isInitializedByInitFieldMacro() );
|
|
m_fieldValue = fieldValue;
|
|
return *this;
|
|
}
|
|
|
|
// Basic access
|
|
|
|
DataType value() const { return m_fieldValue; }
|
|
void setValue( const DataType& fieldValue )
|
|
{
|
|
CAF_ASSERT( isInitializedByInitFieldMacro() );
|
|
m_fieldValue = fieldValue;
|
|
}
|
|
void setValueWithFieldChanged( const DataType& fieldValue );
|
|
|
|
// Implementation of PdmValueField interface
|
|
|
|
QVariant toQVariant() const override
|
|
{
|
|
CAF_ASSERT( isInitializedByInitFieldMacro() );
|
|
using caf::pdmToVariant;
|
|
return pdmToVariant( m_fieldValue );
|
|
}
|
|
void setFromQVariant( const QVariant& variant ) override
|
|
{
|
|
CAF_ASSERT( isInitializedByInitFieldMacro() );
|
|
using caf::pdmFromVariant;
|
|
pdmFromVariant( variant, m_fieldValue );
|
|
}
|
|
bool isReadOnly() const override { return false; }
|
|
|
|
// Access operators
|
|
|
|
/*Conversion */ operator DataType() const { return m_fieldValue; }
|
|
const DataType& operator()() const { return m_fieldValue; }
|
|
|
|
DataType& v() { return m_fieldValue; } // This one breaches encapsulation. Remove ?
|
|
const DataType& v() const { return m_fieldValue; }
|
|
|
|
bool operator==( const DataType& fieldValue ) const { return m_fieldValue == fieldValue; }
|
|
bool operator!=( const DataType& fieldValue ) const { return m_fieldValue != fieldValue; }
|
|
|
|
// Range validation - only available for arithmetic types
|
|
template <typename T = DataType>
|
|
typename std::enable_if<std::is_arithmetic<T>::value>::type setRange( const DataType& minValue, const DataType& maxValue )
|
|
{
|
|
m_minValue = std::min( minValue, maxValue );
|
|
m_maxValue = std::max( minValue, maxValue );
|
|
}
|
|
|
|
template <typename T = DataType>
|
|
typename std::enable_if<std::is_arithmetic<T>::value>::type clearRange()
|
|
{
|
|
m_minValue.reset();
|
|
m_maxValue.reset();
|
|
}
|
|
|
|
template <typename T = DataType>
|
|
typename std::enable_if<std::is_arithmetic<T>::value>::type setMinValue( const DataType& minValue )
|
|
{
|
|
m_minValue = minValue;
|
|
}
|
|
|
|
template <typename T = DataType>
|
|
typename std::enable_if<std::is_arithmetic<T>::value>::type setMaxValue( const DataType& maxValue )
|
|
{
|
|
m_maxValue = maxValue;
|
|
}
|
|
|
|
template <typename T = DataType>
|
|
typename std::enable_if<std::is_arithmetic<T>::value>::type clearMinValue()
|
|
{
|
|
m_minValue.reset();
|
|
}
|
|
|
|
template <typename T = DataType>
|
|
typename std::enable_if<std::is_arithmetic<T>::value>::type clearMaxValue()
|
|
{
|
|
m_maxValue.reset();
|
|
}
|
|
|
|
// Range validation for std::pair<bool, ArithmeticType> - validates the second (value) element
|
|
template <typename T = DataType>
|
|
typename std::enable_if<is_bool_arithmetic_pair<T>::value>::type
|
|
setRange( const typename T::second_type& minValue, const typename T::second_type& maxValue )
|
|
{
|
|
m_minValue = DataType( false, std::min( minValue, maxValue ) );
|
|
m_maxValue = DataType( false, std::max( minValue, maxValue ) );
|
|
}
|
|
|
|
template <typename T = DataType>
|
|
typename std::enable_if<is_bool_arithmetic_pair<T>::value>::type setMinValue( const typename T::second_type& minValue )
|
|
{
|
|
m_minValue = DataType( false, minValue );
|
|
}
|
|
|
|
template <typename T = DataType>
|
|
typename std::enable_if<is_bool_arithmetic_pair<T>::value>::type setMaxValue( const typename T::second_type& maxValue )
|
|
{
|
|
m_maxValue = DataType( false, maxValue );
|
|
}
|
|
|
|
template <typename T = DataType>
|
|
typename std::enable_if<is_bool_arithmetic_pair<T>::value>::type clearRange()
|
|
{
|
|
m_minValue.reset();
|
|
m_maxValue.reset();
|
|
}
|
|
|
|
template <typename T = DataType>
|
|
typename std::enable_if<is_bool_arithmetic_pair<T>::value>::type clearMinValue()
|
|
{
|
|
m_minValue.reset();
|
|
}
|
|
|
|
template <typename T = DataType>
|
|
typename std::enable_if<is_bool_arithmetic_pair<T>::value>::type clearMaxValue()
|
|
{
|
|
m_maxValue.reset();
|
|
}
|
|
|
|
// Override validate from PdmFieldHandle
|
|
QString validate() const override;
|
|
|
|
// Clamp value to range if defined
|
|
DataType clampValue( const DataType& value ) const
|
|
{
|
|
if constexpr ( std::is_arithmetic<DataType>::value )
|
|
{
|
|
DataType clampedValue = value;
|
|
if ( m_minValue.has_value() && clampedValue < m_minValue.value() )
|
|
{
|
|
clampedValue = m_minValue.value();
|
|
}
|
|
if ( m_maxValue.has_value() && clampedValue > m_maxValue.value() )
|
|
{
|
|
clampedValue = m_maxValue.value();
|
|
}
|
|
return clampedValue;
|
|
}
|
|
else if constexpr ( is_bool_arithmetic_pair<DataType>::value )
|
|
{
|
|
DataType clampedValue = value;
|
|
if ( m_minValue.has_value() && clampedValue.second < m_minValue.value().second )
|
|
{
|
|
clampedValue.second = m_minValue.value().second;
|
|
}
|
|
if ( m_maxValue.has_value() && clampedValue.second > m_maxValue.value().second )
|
|
{
|
|
clampedValue.second = m_maxValue.value().second;
|
|
}
|
|
return clampedValue;
|
|
}
|
|
else
|
|
{
|
|
return value;
|
|
}
|
|
}
|
|
|
|
protected:
|
|
DataType m_fieldValue;
|
|
|
|
// Default value stuff.
|
|
//
|
|
// This is not used enough. Remove when dust has settled.
|
|
// ResInsight uses at one point to find whether the value is changed by the user
|
|
public:
|
|
const DataType& defaultValue() const { return m_defaultFieldValue; }
|
|
void setDefaultValue( const DataType& val ) { m_defaultFieldValue = val; }
|
|
|
|
protected:
|
|
DataType m_defaultFieldValue;
|
|
|
|
// Range validation members
|
|
std::optional<DataType> m_minValue;
|
|
std::optional<DataType> m_maxValue;
|
|
};
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
template <typename DataType>
|
|
void caf::PdmDataValueField<DataType>::setValueWithFieldChanged( const DataType& fieldValue )
|
|
{
|
|
CAF_ASSERT( isInitializedByInitFieldMacro() );
|
|
|
|
PdmUiFieldHandleInterface* uiFieldHandleInterface = capability<PdmUiFieldHandleInterface>();
|
|
if ( uiFieldHandleInterface )
|
|
{
|
|
QVariant oldValue = uiFieldHandleInterface->toUiBasedQVariant();
|
|
|
|
m_fieldValue = fieldValue;
|
|
|
|
QVariant newUiBasedQVariant = uiFieldHandleInterface->toUiBasedQVariant();
|
|
|
|
uiFieldHandleInterface->notifyFieldChanged( oldValue, newUiBasedQVariant );
|
|
}
|
|
else
|
|
{
|
|
m_fieldValue = fieldValue;
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Validates the field value against optional range constraints.
|
|
/// Empty QString means valid, non-empty QString contains error message.
|
|
//--------------------------------------------------------------------------------------------------
|
|
template <typename DataType>
|
|
QString caf::PdmDataValueField<DataType>::validate() const
|
|
{
|
|
if constexpr ( std::is_arithmetic<DataType>::value )
|
|
{
|
|
if ( m_minValue.has_value() && m_fieldValue < m_minValue.value() )
|
|
{
|
|
return QString( "Value %1 is below minimum %2" ).arg( m_fieldValue ).arg( m_minValue.value() );
|
|
}
|
|
if ( m_maxValue.has_value() && m_fieldValue > m_maxValue.value() )
|
|
{
|
|
return QString( "Value %1 exceeds maximum %2" ).arg( m_fieldValue ).arg( m_maxValue.value() );
|
|
}
|
|
}
|
|
else if constexpr ( is_bool_arithmetic_pair<DataType>::value )
|
|
{
|
|
if ( m_minValue.has_value() && m_fieldValue.second < m_minValue.value().second )
|
|
{
|
|
return QString( "Value %1 is below minimum %2" ).arg( m_fieldValue.second ).arg( m_minValue.value().second );
|
|
}
|
|
if ( m_maxValue.has_value() && m_fieldValue.second > m_maxValue.value().second )
|
|
{
|
|
return QString( "Value %1 exceeds maximum %2" ).arg( m_fieldValue.second ).arg( m_maxValue.value().second );
|
|
}
|
|
}
|
|
return executeCustomValidation();
|
|
}
|
|
|
|
} // End of namespace caf
|