diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafInternalPdmValueFieldSpecializations.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafInternalPdmValueFieldSpecializations.h index d44194514a..ad472c2cae 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafInternalPdmValueFieldSpecializations.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafInternalPdmValueFieldSpecializations.h @@ -134,6 +134,47 @@ public: } }; +//================================================================================================== +/// Partial specialization for std::pair +//================================================================================================== +template +class PdmValueFieldSpecialization> +{ +public: + static QVariant convert( const std::pair& value ) + { + QList returnList; + + returnList.push_back( PdmValueFieldSpecialization::convert( value.first ) ); + returnList.push_back( PdmValueFieldSpecialization::convert( value.second ) ); + + return returnList; + } + + static void setFromVariant( const QVariant& variantValue, std::pair& value ) + { + if ( variantValue.canConvert>() ) + { + QList lst = variantValue.toList(); + if ( lst.size() == 2 ) + { + T first; + PdmValueFieldSpecialization::setFromVariant( lst[0], first ); + + U second; + PdmValueFieldSpecialization::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 //================================================================================================== diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafInternalPdmFieldTypeSpecializations.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafInternalPdmFieldTypeSpecializations.h index ec8a7dcdb9..b07a0da80b 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafInternalPdmFieldTypeSpecializations.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafInternalPdmFieldTypeSpecializations.h @@ -179,6 +179,41 @@ public: } }; +template +class PdmUiFieldSpecialization> +{ +public: + /// Convert the field value into a QVariant + static QVariant convert( const std::pair& value ) + { + return PdmValueFieldSpecialization>::convert( value ); + } + + /// Set the field value from a QVariant + static void setFromVariant( const QVariant& variantValue, std::pair& value ) + { + PdmValueFieldSpecialization>::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 valueOptions( const std::pair& ) + { + QList optionList; + + return optionList; + } + + /// Methods to retrieve the possible PdmObject pointed to by a field + static void childObjects( const PdmDataValueField>& field, std::vector* objects ) + { + } +}; + //================================================================================================== /// Partial specialization for FilePath //================================================================================================== diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiFieldSpecialization.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiFieldSpecialization.h index 59287a8e58..126133effc 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiFieldSpecialization.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiFieldSpecialization.h @@ -27,11 +27,17 @@ template 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(); } + static void setFromVariant( const QVariant& variantValue, T& value ) + { + /// Set the field value from a QVariant + value = variantValue.value(); + } /// Check equality between QVariants that carries a Field Value. /// The == operator will normally work, but does not support custom types in the QVariant diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafInternalPdmStreamOperators.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafInternalPdmStreamOperators.h index d7836845dc..024c67b269 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafInternalPdmStreamOperators.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafInternalPdmStreamOperators.h @@ -62,3 +62,48 @@ QTextStream& operator>>( QTextStream& str, std::vector& sobj ) } return str; } + +//================================================================================================== +/// QTextStream Stream operator overloading for std::pair +//================================================================================================== + +template +QTextStream& operator<<( QTextStream& str, const std::pair& sobj ) +{ + str << sobj.first; + str << " "; + str << sobj.second; + + return str; +} + +template +QTextStream& operator>>( QTextStream& str, std::pair& 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(); + + sobj = std::make_pair( first, second ); + + return str; +} diff --git a/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/AggregatedTypesInField.cpp b/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/AggregatedTypesInField.cpp new file mode 100644 index 0000000000..31032b898b --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/AggregatedTypesInField.cpp @@ -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 <> +// 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 <> +// for more details. +// +//################################################################################################## + +#include "gtest/gtest.h" + +#include "cafPdmField.h" +#include "cafPdmObject.h" + +#include + +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> 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 ); + } +} diff --git a/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/CMakeLists.txt b/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/CMakeLists.txt index 97e566aace..c069df4217 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/CMakeLists.txt +++ b/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/CMakeLists.txt @@ -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 diff --git a/Fwk/AppFwk/cafTests/cafTestApplication/MainWindow.cpp b/Fwk/AppFwk/cafTests/cafTestApplication/MainWindow.cpp index 920563e3a6..9baff4a510 100644 --- a/Fwk/AppFwk/cafTests/cafTestApplication/MainWindow.cpp +++ b/Fwk/AppFwk/cafTests/cafTestApplication/MainWindow.cpp @@ -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 m_intField; caf::PdmField m_textField; + caf::PdmField> m_booleanAndDoubleField; + caf::PdmField> m_booleanAndTextField; + caf::PdmChildArrayField m_colorTriplets; caf::PdmProxyValueField 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); diff --git a/Fwk/AppFwk/cafUserInterface/CMakeLists.txt b/Fwk/AppFwk/cafUserInterface/CMakeLists.txt index 6bab3b419f..8581ee3334 100644 --- a/Fwk/AppFwk/cafUserInterface/CMakeLists.txt +++ b/Fwk/AppFwk/cafUserInterface/CMakeLists.txt @@ -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 diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiCheckBoxAndTextEditor.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiCheckBoxAndTextEditor.cpp new file mode 100644 index 0000000000..14bcf20c52 --- /dev/null +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiCheckBoxAndTextEditor.cpp @@ -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 <> +// 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 <> +// 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 +#include +#include + +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> + auto variantValue = uiField()->uiValue(); + if ( variantValue.canConvert>() ) + { + QList 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>::convert( pairValue ); + + this->setValueToField( v ); +} + +} // end namespace caf diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiCheckBoxAndTextEditor.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiCheckBoxAndTextEditor.h new file mode 100644 index 0000000000..0b4e809f60 --- /dev/null +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiCheckBoxAndTextEditor.h @@ -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 <> +// 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 <> +// for more details. +// +//################################################################################################## + +#pragma once + +#include "cafPdmUiFieldEditorHandle.h" + +#include +#include +#include +#include +#include +#include + +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 m_lineEdit; + QPointer m_checkBox; + QPointer m_label; +}; + +} // end namespace caf diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiDefaultObjectEditor.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiDefaultObjectEditor.cpp index fe3339f581..7aca7dd30e 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiDefaultObjectEditor.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiDefaultObjectEditor.cpp @@ -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 +#include + namespace caf { // Register default field editor for selected types @@ -69,6 +72,15 @@ CAF_PDM_UI_REGISTER_DEFAULT_FIELD_EDITOR( PdmUiListEditor, std::vector ); 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 the +// registration of this type in the factory has to be written directly +static bool myPdmUiCheckBoxAndTextEditor73 = + caf::Factory::instance()->registerCreator( + QString( typeid( caf::PdmField> ).name() ) ); +static bool my2PdmUiCheckBoxAndTextEditor73 = + caf::Factory::instance()->registerCreator( + QString( typeid( caf::PdmProxyValueField> ).name() ) ); + //-------------------------------------------------------------------------------------------------- /// //--------------------------------------------------------------------------------------------------