Add support for field of std::pair<T, U>

This commit is contained in:
Magne Sjaastad 2023-03-31 10:21:56 +02:00 committed by GitHub
parent c40b400346
commit ee1b363ae0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 484 additions and 6 deletions

View File

@ -134,6 +134,47 @@ public:
}
};
//==================================================================================================
/// 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
//==================================================================================================

View File

@ -179,6 +179,41 @@ public:
}
};
template <typename T, typename U>
class PdmUiFieldSpecialization<std::pair<T, U>>
{
public:
/// Convert the field value into a QVariant
static QVariant convert( const std::pair<T, U>& value )
{
return PdmValueFieldSpecialization<std::pair<T, U>>::convert( value );
}
/// Set the field value from a QVariant
static void setFromVariant( const QVariant& variantValue, std::pair<T, U>& value )
{
PdmValueFieldSpecialization<std::pair<T, U>>::setFromVariant( variantValue, value );
}
static bool isDataElementEqual( const QVariant& variantValue, const QVariant& variantValue2 )
{
return variantValue == variantValue2;
}
/// Methods to get a list of options for a field, specialized for AppEnum
static QList<PdmOptionItemInfo> valueOptions( const std::pair<T, U>& )
{
QList<PdmOptionItemInfo> optionList;
return optionList;
}
/// Methods to retrieve the possible PdmObject pointed to by a field
static void childObjects( const PdmDataValueField<caf::AppEnum<T>>& field, std::vector<PdmObjectHandle*>* objects )
{
}
};
//==================================================================================================
/// Partial specialization for FilePath
//==================================================================================================

View File

@ -27,11 +27,17 @@ template <typename T>
class PdmUiFieldSpecialization
{
public:
/// Convert the field value into a QVariant
static QVariant convert( const T& value ) { return QVariant::fromValue( value ); }
static QVariant convert( const T& value )
{
/// Convert the field value into a QVariant
return QVariant::fromValue( value );
}
/// Set the field value from a QVariant
static void setFromVariant( const QVariant& variantValue, T& value ) { value = variantValue.value<T>(); }
static void setFromVariant( const QVariant& variantValue, T& value )
{
/// Set the field value from a QVariant
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

View File

@ -62,3 +62,48 @@ QTextStream& operator>>( QTextStream& str, std::vector<T>& sobj )
}
return str;
}
//==================================================================================================
/// QTextStream Stream operator overloading for std::pair<T, U>
//==================================================================================================
template <typename T, typename U>
QTextStream& operator<<( QTextStream& str, const std::pair<T, U>& sobj )
{
str << sobj.first;
str << " ";
str << sobj.second;
return str;
}
template <typename T, typename U>
QTextStream& operator>>( QTextStream& str, std::pair<T, U>& sobj )
{
T first;
str >> first;
QString restOfString;
while ( str.status() == QTextStream::Ok )
{
// Using the >> operator will parse a string word by word. Multiple spaces between words will be replaced by a
// single space.
QString tmp;
str >> tmp;
if ( !tmp.isEmpty() )
{
if ( !restOfString.isEmpty() ) restOfString += " ";
restOfString += tmp;
}
}
QVariant v = restOfString;
U second = v.value<U>();
sobj = std::make_pair( first, second );
return str;
}

View File

@ -0,0 +1,102 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2013 Ceetron Solutions 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.
//
//##################################################################################################
#include "gtest/gtest.h"
#include "cafPdmField.h"
#include "cafPdmObject.h"
#include <utility>
class AggregatedTypes : public caf::PdmObject
{
CAF_PDM_HEADER_INIT;
public:
AggregatedTypes()
{
CAF_PDM_InitObject( "SimpleObj" );
auto pair = std::make_pair( false, 12.0 );
CAF_PDM_InitField( &m_checkableDouble, "CheckableDouble", pair, "label text" );
}
~AggregatedTypes() {}
caf::PdmField<std::pair<bool, double>> m_checkableDouble;
};
CAF_PDM_SOURCE_INIT( AggregatedTypes, "AggregatedTypes" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( AggregatedTypes, AggregatedTypes )
{
AggregatedTypes obj;
EXPECT_EQ( obj.m_checkableDouble().first, false );
EXPECT_EQ( obj.m_checkableDouble().second, 12.0 );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( AggregatedTypeTest, MyTest )
{
QString xml;
QXmlStreamWriter xmlStream( &xml );
xmlStream.setAutoFormatting( true );
const double testValue = 0.0012;
{
AggregatedTypes myObj;
auto testPair = std::make_pair( true, testValue );
myObj.m_checkableDouble = testPair;
xml = myObj.writeObjectToXmlString();
}
{
AggregatedTypes myObj;
myObj.readObjectFromXmlString( xml, caf::PdmDefaultObjectFactory::instance() );
auto fieldValue = myObj.m_checkableDouble();
ASSERT_TRUE( fieldValue.first );
ASSERT_DOUBLE_EQ( testValue, fieldValue.second );
}
}

View File

@ -8,7 +8,7 @@ find_package(
COMPONENTS
REQUIRED Core Xml Gui
)
set(QT_LIBRARIES Qt5::Core Qt5::Xml Qt5::Gui)
set(QT_LIBRARIES Qt5::Core Qt5::Xml Qt5::Gui Qt5::Widgets)
if(MSVC AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 19.11))
# VS 2017 : Disable warnings from from gtest code, using deprecated code
@ -20,7 +20,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} # required for gtest-all.cpp
)
set(PROJECT_FILES cafPdmBasicTest.cpp cafProjectDataModel_UnitTests.cpp
Child.cpp Parent.cpp TestObj.cpp
Child.cpp Parent.cpp TestObj.cpp AggregatedTypesInField.cpp
)
# add the executable

View File

@ -26,6 +26,7 @@
#include "cafPdmProxyValueField.h"
#include "cafPdmPtrField.h"
#include "cafPdmReferenceHelper.h"
#include "cafPdmUiCheckBoxAndTextEditor.h"
#include "cafPdmUiCheckBoxEditor.h"
#include "cafPdmUiColorEditor.h"
#include "cafPdmUiComboBoxEditor.h"
@ -129,6 +130,10 @@ public:
"Text tooltip",
"This is a place you can enter a small integer value if you want");
CAF_PDM_InitFieldNoDefault(&m_booleanAndDoubleField, "BooleanAndDoubleField", "Checkable double");
CAF_PDM_InitFieldNoDefault(&m_booleanAndTextField, "BooleanAndTextField", "Checkable text");
m_booleanAndTextField.uiCapability()->setUiEditorTypeName(caf::PdmUiCheckBoxAndTextEditor::uiEditorTypeName());
m_proxyDoubleField.registerSetMethod(this, &SmallDemoPdmObject::setDoubleMember);
m_proxyDoubleField.registerGetMethod(this, &SmallDemoPdmObject::doubleMember);
CAF_PDM_InitFieldNoDefault(&m_proxyDoubleField, "ProxyDouble", "Proxy Double");
@ -164,6 +169,9 @@ public:
caf::PdmField<int> m_intField;
caf::PdmField<QString> m_textField;
caf::PdmField<std::pair<bool, double>> m_booleanAndDoubleField;
caf::PdmField<std::pair<bool, QString>> m_booleanAndTextField;
caf::PdmChildArrayField<ColorTriplet*> m_colorTriplets;
caf::PdmProxyValueField<double> m_proxyDoubleField;
@ -279,6 +287,9 @@ protected:
//--------------------------------------------------------------------------------------------------
void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override
{
uiOrdering.add(&m_booleanAndDoubleField);
uiOrdering.add(&m_booleanAndTextField);
uiOrdering.add(&m_doubleField);
uiOrdering.add(&m_intField);
QString dynamicGroupName = QString("Dynamic Group Text (%1)").arg(m_intField);

View File

@ -51,6 +51,7 @@ set(MOC_HEADER_FILES
cafPdmDoubleStringValidator.h
cafPdmUiPickableLineEditor.h
cafPdmUiLabelEditor.h
cafPdmUiCheckBoxAndTextEditor.h
)
find_package(
@ -105,6 +106,8 @@ set(PROJECT_FILES
cafPdmUiFieldEditorHelper.h
cafPdmUiFieldEditorHelper.cpp
cafPdmUiLabelEditor.cpp
cafPdmUiCheckBoxAndTextEditor.h
cafPdmUiCheckBoxAndTextEditor.cpp
# object editors
cafPdmUiDefaultObjectEditor.cpp
cafPdmUiDefaultObjectEditor.h

View File

@ -0,0 +1,147 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2023 Ceetron Solutions 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.
//
//##################################################################################################
#include "cafPdmUiCheckBoxAndTextEditor.h"
#include "cafPdmField.h"
#include "cafPdmObject.h"
#include "cafPdmUiDefaultObjectEditor.h"
#include "cafPdmUiFieldEditorHandle.h"
#include "cafPdmUiLineEditor.h"
#include "cafPdmUiOrdering.h"
#include "cafQShortenedLabel.h"
#include <QHBoxLayout>
#include <QLabel>
#include <QTextEdit>
namespace caf
{
CAF_PDM_UI_FIELD_EDITOR_SOURCE_INIT( PdmUiCheckBoxAndTextEditor );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiCheckBoxAndTextEditor::configureAndUpdateUi( const QString& uiConfigName )
{
CAF_ASSERT( !m_lineEdit.isNull() );
CAF_ASSERT( !m_label.isNull() );
PdmUiFieldEditorHandle::updateLabelFromField( m_label, uiConfigName );
m_lineEdit->setToolTip( uiField()->uiToolTip( uiConfigName ) );
bool isChecked = false;
QString textString;
// A pair is converted into a list of QVariant in PdmValueFieldSpecialization<std::pair<T, U>>
auto variantValue = uiField()->uiValue();
if ( variantValue.canConvert<QList<QVariant>>() )
{
QList<QVariant> lst = variantValue.toList();
if ( lst.size() == 2 )
{
isChecked = lst[0].toBool();
textString = lst[1].toString();
}
}
m_lineEdit->blockSignals( true );
m_checkBox->blockSignals( true );
m_lineEdit->setText( QString( "%1" ).arg( textString ) );
m_checkBox->setChecked( isChecked );
m_lineEdit->blockSignals( false );
m_checkBox->blockSignals( false );
bool isReadOnly = uiField()->isUiReadOnly( uiConfigName );
if ( !isChecked ) isReadOnly = true;
m_lineEdit->setDisabled( isReadOnly );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QWidget* PdmUiCheckBoxAndTextEditor::createEditorWidget( QWidget* parent )
{
auto* containerWidget = new QWidget( parent );
auto lineEditWidget = new PdmUiLineEdit( containerWidget );
lineEditWidget->setAvoidSendingEnterEventToParentWidget( true );
m_lineEdit = lineEditWidget;
connect( m_lineEdit, SIGNAL( editingFinished() ), this, SLOT( slotSetValueToField() ) );
m_checkBox = new QCheckBox( "", containerWidget );
connect( m_checkBox, SIGNAL( clicked() ), this, SLOT( slotSetValueToField() ) );
auto* layout = new QHBoxLayout;
layout->addWidget( m_checkBox );
layout->addWidget( m_lineEdit );
layout->setMargin( 0 );
containerWidget->setLayout( layout );
return containerWidget;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QWidget* PdmUiCheckBoxAndTextEditor::createLabelWidget( QWidget* parent )
{
m_label = new QShortenedLabel( parent );
return m_label;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiCheckBoxAndTextEditor::slotSetValueToField()
{
bool isChecked = m_checkBox->checkState() == Qt::CheckState::Checked;
auto text = m_lineEdit->text();
auto pairValue = std::make_pair( isChecked, text );
QVariant v = caf::PdmValueFieldSpecialization<std::pair<bool, QString>>::convert( pairValue );
this->setValueToField( v );
}
} // end namespace caf

View File

@ -0,0 +1,76 @@
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2023 Ceetron Solutions 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.
//
//##################################################################################################
#pragma once
#include "cafPdmUiFieldEditorHandle.h"
#include <QCheckBox>
#include <QLabel>
#include <QLineEdit>
#include <QPointer>
#include <QString>
#include <QWidget>
namespace caf
{
//==================================================================================================
///
//==================================================================================================
class PdmUiCheckBoxAndTextEditor : public PdmUiFieldEditorHandle
{
Q_OBJECT
CAF_PDM_UI_FIELD_EDITOR_HEADER_INIT;
public:
PdmUiCheckBoxAndTextEditor() {}
~PdmUiCheckBoxAndTextEditor() override {}
protected:
QWidget* createEditorWidget( QWidget* parent ) override;
QWidget* createLabelWidget( QWidget* parent ) override;
void configureAndUpdateUi( const QString& uiConfigName ) override;
protected slots:
void slotSetValueToField();
private:
QPointer<QLineEdit> m_lineEdit;
QPointer<QCheckBox> m_checkBox;
QPointer<QShortenedLabel> m_label;
};
} // end namespace caf

View File

@ -39,6 +39,7 @@
#include "cafFilePath.h"
#include "cafPdmField.h"
#include "cafPdmProxyValueField.h"
#include "cafPdmUiCheckBoxAndTextEditor.h"
#include "cafPdmUiCheckBoxEditor.h"
#include "cafPdmUiDateEditor.h"
#include "cafPdmUiFieldEditorHandle.h"
@ -49,6 +50,8 @@
#include <QGridLayout>
#include <utility>
namespace caf
{
// Register default field editor for selected types
@ -69,6 +72,15 @@ CAF_PDM_UI_REGISTER_DEFAULT_FIELD_EDITOR( PdmUiListEditor, std::vector<float> );
CAF_PDM_UI_REGISTER_DEFAULT_FIELD_EDITOR( PdmUiFilePathEditor, FilePath );
// As the macro CAF_PDM_UI_REGISTER_DEFAULT_FIELD_EDITOR() is not working correctly for std::pair<bool, double> the
// registration of this type in the factory has to be written directly
static bool myPdmUiCheckBoxAndTextEditor73 =
caf::Factory<caf::PdmUiFieldEditorHandle, QString>::instance()->registerCreator<PdmUiCheckBoxAndTextEditor>(
QString( typeid( caf::PdmField<std::pair<bool, double>> ).name() ) );
static bool my2PdmUiCheckBoxAndTextEditor73 =
caf::Factory<caf::PdmUiFieldEditorHandle, QString>::instance()->registerCreator<PdmUiCheckBoxAndTextEditor>(
QString( typeid( caf::PdmProxyValueField<std::pair<bool, double>> ).name() ) );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------