Refactors PdmUiItemInfo and PdmOptionItemInfo

Refactors PdmUiItem and moves PdmUiItemInfo and PdmOptionItemInfo classes.

Adds attribute support as a replacement for defineEditorAttributes
This commit is contained in:
Magne Sjaastad committed 2026-01-08 21:44:58 +01:00
1 parent 51b9508483
commit 6e23037bb8
8 files changed
+748 -394

No files matched your search

@@ -28,6 +28,10 @@ set(PROJECT_FILES
cafPdmUiFieldSpecialization.h
cafPdmUiItem.cpp
cafPdmUiItem.h
cafPdmUiItemInfo.cpp
cafPdmUiItemInfo.h
cafPdmOptionItemInfo.cpp
cafPdmOptionItemInfo.h
cafPdmUiModelChangeDetector.cpp
cafPdmUiModelChangeDetector.h
cafPdmUiObjectEditorHandle.cpp
@@ -0,0 +1,155 @@
//##################################################################################################
//
// 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.
//
//##################################################################################################
#include "cafPdmOptionItemInfo.h"
#include "cafPdmObjectHandle.h"
#include "cafPdmPointer.h"
namespace caf
{
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
PdmOptionItemInfo::PdmOptionItemInfo( const QString& anOptionUiText,
const QVariant& aValue,
bool isReadOnly,
const IconProvider& anIcon )
: m_optionUiText( anOptionUiText )
, m_value( aValue )
, m_isReadOnly( isReadOnly )
, m_iconProvider( anIcon )
, m_level( 0 )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
PdmOptionItemInfo::PdmOptionItemInfo( const QString& anOptionUiText,
caf::PdmObjectHandle* obj,
bool isReadOnly,
const IconProvider& anIcon )
: m_optionUiText( anOptionUiText )
, m_isReadOnly( isReadOnly )
, m_iconProvider( anIcon )
, m_level( 0 )
{
m_value = QVariant::fromValue( caf::PdmPointer<caf::PdmObjectHandle>( obj ) );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
PdmOptionItemInfo PdmOptionItemInfo::createHeader( const QString& anOptionUiText, bool isReadOnly, const IconProvider& anIcon )
{
PdmOptionItemInfo header( anOptionUiText, QVariant(), isReadOnly, anIcon );
return header;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmOptionItemInfo::setLevel( int level )
{
m_level = level;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString PdmOptionItemInfo::optionUiText() const
{
return m_optionUiText;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QVariant PdmOptionItemInfo::value() const
{
return m_value;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool PdmOptionItemInfo::isReadOnly() const
{
return m_isReadOnly;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool PdmOptionItemInfo::isHeading() const
{
return !m_value.isValid();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::unique_ptr<QIcon> PdmOptionItemInfo::icon() const
{
return m_iconProvider.icon();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int PdmOptionItemInfo::level() const
{
return m_level;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QStringList PdmOptionItemInfo::extractUiTexts( const QList<PdmOptionItemInfo>& optionList )
{
QStringList texts;
for ( const auto& option : optionList )
{
texts.push_back( option.optionUiText() );
}
return texts;
}
} // End of namespace caf
@@ -0,0 +1,178 @@
//##################################################################################################
//
// 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.
//
//##################################################################################################
#pragma once
#include "cafIconProvider.h"
#include "cafPdmUiFieldSpecialization.h"
#include <memory>
#include <type_traits>
#include <vector>
class QIcon;
namespace caf
{
class PdmObjectHandle;
//==================================================================================================
/// Class to keep Ui information about an option /choice in a Combobox or similar.
//==================================================================================================
class PdmOptionItemInfo
{
public:
// Template pass-through for enum types, ensuring the T type gets cast to an int before storing in the QVariant
// Note the extra dummy parameter. This ensures compilation fails for non-enum types and these variants get removed
// due to SFINAE (https://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error)
template <typename T>
PdmOptionItemInfo( const QString& anOptionUiText,
T aValue,
bool isReadOnly = false,
const IconProvider& anIcon = IconProvider(),
typename std::enable_if<std::is_enum<T>::value>::type* = 0 )
: PdmOptionItemInfo( anOptionUiText, QVariant( static_cast<int>( aValue ) ), isReadOnly, anIcon )
{
}
PdmOptionItemInfo( const QString& anOptionUiText,
const QVariant& aValue,
bool isReadOnly = false,
const IconProvider& anIcon = IconProvider() );
PdmOptionItemInfo( const QString& anOptionUiText,
caf::PdmObjectHandle* obj,
bool isReadOnly = false,
const IconProvider& anIcon = IconProvider() );
static PdmOptionItemInfo createHeader( const QString& anOptionUiText,
bool isReadOnly = false,
const IconProvider& anIcon = IconProvider() );
void setLevel( int level );
QString optionUiText() const;
QVariant value() const;
bool isReadOnly() const;
bool isHeading() const;
std::unique_ptr<QIcon> icon() const;
int level() const;
// Static utility methods to handle QList of PdmOptionItemInfo
// Please regard as private to the PDM system
static QStringList extractUiTexts( const QList<PdmOptionItemInfo>& optionList );
template <typename T>
static bool findValues( const QList<PdmOptionItemInfo>& optionList,
QVariant fieldValue,
std::vector<unsigned int>& foundIndexes );
private:
QString m_optionUiText;
QVariant m_value;
bool m_isReadOnly;
IconProvider m_iconProvider;
int m_level;
};
//--------------------------------------------------------------------------------------------------
/// Finds the indexes into the optionList that the field value(s) corresponds to.
/// In the case where the field is some kind of array, several indexes might be returned
/// The returned bool is true if all the fieldValues were found.
//--------------------------------------------------------------------------------------------------
template <typename T>
bool PdmOptionItemInfo::findValues( const QList<PdmOptionItemInfo>& optionList,
QVariant fieldValue,
std::vector<unsigned int>& foundIndexes )
{
foundIndexes.clear();
// Find this fieldvalue in the optionlist if present
// First handle lists/arrays of values
if ( fieldValue.metaType().id() == QMetaType::QVariantList )
{
QList<QVariant> valuesSelectedInField = fieldValue.toList();
if ( !valuesSelectedInField.empty() )
{
// Create a list to be able to remove items as they are matched with values
std::list<std::pair<QVariant, unsigned int>> optionVariantAndIndexPairs;
for ( int i = 0; i < optionList.size(); ++i )
{
optionVariantAndIndexPairs.push_back( std::make_pair( optionList[i].value(), i ) );
}
for ( const auto& value : valuesSelectedInField )
{
std::list<std::pair<QVariant, unsigned int>>::iterator it;
for ( it = optionVariantAndIndexPairs.begin(); it != optionVariantAndIndexPairs.end(); ++it )
{
if ( PdmUiFieldSpecialization<T>::isDataElementEqual( value, it->first ) )
{
foundIndexes.push_back( it->second );
// Assuming that one option is referenced only once, the option is erased. Then break
// out of the inner loop, as this operation can be costly for fields with many options and many
// values
optionVariantAndIndexPairs.erase( it );
break;
}
}
}
}
return ( static_cast<size_t>( valuesSelectedInField.size() ) <= foundIndexes.size() );
}
else // Then handle single value fields
{
for ( unsigned int opIdx = 0; opIdx < static_cast<unsigned int>( optionList.size() ); ++opIdx )
{
if ( PdmUiFieldSpecialization<T>::isDataElementEqual( optionList[opIdx].value(), fieldValue ) )
{
foundIndexes.push_back( opIdx );
break;
}
}
return ( !foundIndexes.empty() );
}
}
} // End of namespace caf
@@ -3,7 +3,7 @@
// 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
// This library may be used under the terms of the GNU General Public License or
// the GNU Lesser General Public License as follows:
//
// GNU General Public License Usage
@@ -35,189 +35,15 @@
//##################################################################################################
#include "cafPdmUiItem.h"
#include "cafPdmLogging.h"
#include "cafPdmOptionItemInfo.h"
#include "cafPdmUiEditorHandle.h"
#include "cafPdmUiItemInfo.h"
#include "cafPdmUiObjectEditorHandle.h"
#include "cafUpdateEditorsScheduler.h"
namespace caf
{
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
PdmUiItemInfo::PdmUiItemInfo( const QString& uiName,
IconProvider iconProvider /*= IconProvider() */,
QString toolTip /*= ""*/,
QString whatsThis /*= ""*/,
QString extraDebugText /*= ""*/ )
: m_uiName( uiName )
, m_iconProvider( iconProvider )
, m_toolTip( toolTip )
, m_whatsThis( whatsThis )
, m_extraDebugText( extraDebugText )
, m_editorTypeName( "" )
, m_isHidden( false )
, m_isTreeHidden( false )
, m_isTreeChildrenHidden( false )
, m_isReadOnly( false )
, m_labelAlignment( LEFT )
, m_isCustomContextMenuEnabled( false )
, m_notifyAllFieldsInMultiFieldChangedEvents( -1 )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
PdmUiItemInfo::PdmUiItemInfo( const QString& uiName,
QString iconResourceLocation /*= ""*/,
QString toolTip /*= ""*/,
QString whatsThis /*= ""*/,
QString extraDebugText /*= ""*/ )
: m_uiName( uiName )
, m_iconProvider( iconResourceLocation )
, m_toolTip( toolTip )
, m_whatsThis( whatsThis )
, m_extraDebugText( extraDebugText )
, m_editorTypeName( "" )
, m_isHidden( false )
, m_isTreeHidden( false )
, m_isTreeChildrenHidden( false )
, m_isReadOnly( false )
, m_labelAlignment( LEFT )
, m_isCustomContextMenuEnabled( false )
, m_notifyAllFieldsInMultiFieldChangedEvents( -1 )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::unique_ptr<QIcon> PdmUiItemInfo::icon() const
{
return m_iconProvider.icon();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const IconProvider& PdmUiItemInfo::iconProvider() const
{
return m_iconProvider;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
PdmOptionItemInfo::PdmOptionItemInfo( const QString& anOptionUiText,
const QVariant& aValue,
bool isReadOnly /* = false */,
const IconProvider& anIcon /* = IconProvider()*/ )
: m_optionUiText( anOptionUiText )
, m_value( aValue )
, m_isReadOnly( isReadOnly )
, m_iconProvider( anIcon )
, m_level( 0 )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
PdmOptionItemInfo::PdmOptionItemInfo( const QString& anOptionUiText,
caf::PdmObjectHandle* obj,
bool isReadOnly /*= false*/,
const IconProvider& anIcon /*= IconProvider()*/ )
: m_optionUiText( anOptionUiText )
, m_isReadOnly( isReadOnly )
, m_iconProvider( anIcon )
, m_level( 0 )
{
m_value = QVariant::fromValue( caf::PdmPointer<caf::PdmObjectHandle>( obj ) );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
PdmOptionItemInfo PdmOptionItemInfo::createHeader( const QString& anOptionUiText,
bool isReadOnly /*= false*/,
const IconProvider& anIcon /*= IconProvider()*/ )
{
PdmOptionItemInfo header( anOptionUiText, QVariant(), isReadOnly, anIcon );
return header;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmOptionItemInfo::setLevel( int level )
{
m_level = level;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const QString PdmOptionItemInfo::optionUiText() const
{
return m_optionUiText;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const QVariant PdmOptionItemInfo::value() const
{
return m_value;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool PdmOptionItemInfo::isReadOnly() const
{
return m_isReadOnly;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool PdmOptionItemInfo::isHeading() const
{
return !m_value.isValid();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::unique_ptr<QIcon> PdmOptionItemInfo::icon() const
{
return m_iconProvider.icon();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int PdmOptionItemInfo::level() const
{
return m_level;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QStringList PdmOptionItemInfo::extractUiTexts( const QList<PdmOptionItemInfo>& optionList )
{
QStringList texts;
for ( const auto& option : optionList )
{
texts.push_back( option.optionUiText() );
}
return texts;
}
//==================================================================================================
/// PdmUiItem
//==================================================================================================
@@ -403,9 +229,9 @@ bool PdmUiItem::isUiHidden( const QString& uiConfigName ) const
const PdmUiItemInfo* defInfo = defaultInfo();
const PdmUiItemInfo* sttInfo = m_staticItemInfo;
if ( conInfo && !( conInfo->m_isHidden == -1 ) ) return conInfo->m_isHidden;
if ( defInfo && !( defInfo->m_isHidden == -1 ) ) return defInfo->m_isHidden;
if ( sttInfo && !( sttInfo->m_isHidden == -1 ) ) return sttInfo->m_isHidden;
if ( conInfo && conInfo->m_isHidden.has_value() ) return conInfo->m_isHidden.value();
if ( defInfo && defInfo->m_isHidden.has_value() ) return defInfo->m_isHidden.value();
if ( sttInfo && sttInfo->m_isHidden.has_value() ) return sttInfo->m_isHidden.value();
return false;
}
@@ -427,9 +253,9 @@ bool PdmUiItem::isUiTreeHidden( const QString& uiConfigName ) const
const PdmUiItemInfo* defInfo = defaultInfo();
const PdmUiItemInfo* sttInfo = m_staticItemInfo;
if ( conInfo && !( conInfo->m_isTreeHidden == -1 ) ) return conInfo->m_isTreeHidden;
if ( defInfo && !( defInfo->m_isTreeHidden == -1 ) ) return defInfo->m_isTreeHidden;
if ( sttInfo && !( sttInfo->m_isTreeHidden == -1 ) ) return sttInfo->m_isTreeHidden;
if ( conInfo && conInfo->m_isTreeHidden.has_value() ) return conInfo->m_isTreeHidden.value();
if ( defInfo && defInfo->m_isTreeHidden.has_value() ) return defInfo->m_isTreeHidden.value();
if ( sttInfo && sttInfo->m_isTreeHidden.has_value() ) return sttInfo->m_isTreeHidden.value();
return false;
}
@@ -451,9 +277,9 @@ bool PdmUiItem::isUiTreeChildrenHidden( const QString& uiConfigName ) const
const PdmUiItemInfo* defInfo = defaultInfo();
const PdmUiItemInfo* sttInfo = m_staticItemInfo;
if ( conInfo && !( conInfo->m_isTreeChildrenHidden == -1 ) ) return conInfo->m_isTreeChildrenHidden;
if ( defInfo && !( defInfo->m_isTreeChildrenHidden == -1 ) ) return defInfo->m_isTreeChildrenHidden;
if ( sttInfo && !( sttInfo->m_isTreeChildrenHidden == -1 ) ) return sttInfo->m_isTreeChildrenHidden;
if ( conInfo && conInfo->m_isTreeChildrenHidden.has_value() ) return conInfo->m_isTreeChildrenHidden.value();
if ( defInfo && defInfo->m_isTreeChildrenHidden.has_value() ) return defInfo->m_isTreeChildrenHidden.value();
if ( sttInfo && sttInfo->m_isTreeChildrenHidden.has_value() ) return sttInfo->m_isTreeChildrenHidden.value();
return false;
}
@@ -475,9 +301,9 @@ bool PdmUiItem::isUiReadOnly( const QString& uiConfigName /*= ""*/ ) const
const PdmUiItemInfo* defInfo = defaultInfo();
const PdmUiItemInfo* sttInfo = m_staticItemInfo;
if ( conInfo && !( conInfo->m_isReadOnly == -1 ) ) return conInfo->m_isReadOnly;
if ( defInfo && !( defInfo->m_isReadOnly == -1 ) ) return defInfo->m_isReadOnly;
if ( sttInfo && !( sttInfo->m_isReadOnly == -1 ) ) return sttInfo->m_isReadOnly;
if ( conInfo && conInfo->m_isReadOnly.has_value() ) return conInfo->m_isReadOnly.value();
if ( defInfo && defInfo->m_isReadOnly.has_value() ) return defInfo->m_isReadOnly.value();
if ( sttInfo && sttInfo->m_isReadOnly.has_value() ) return sttInfo->m_isReadOnly.value();
return false;
}
@@ -499,12 +325,12 @@ bool PdmUiItem::notifyAllFieldsInMultiFieldChangedEvents( const QString& uiConfi
const PdmUiItemInfo* defInfo = defaultInfo();
const PdmUiItemInfo* sttInfo = m_staticItemInfo;
if ( conInfo && !( conInfo->m_notifyAllFieldsInMultiFieldChangedEvents == -1 ) )
return conInfo->m_notifyAllFieldsInMultiFieldChangedEvents;
if ( defInfo && !( defInfo->m_notifyAllFieldsInMultiFieldChangedEvents == -1 ) )
return defInfo->m_notifyAllFieldsInMultiFieldChangedEvents;
if ( sttInfo && !( sttInfo->m_notifyAllFieldsInMultiFieldChangedEvents == -1 ) )
return sttInfo->m_notifyAllFieldsInMultiFieldChangedEvents;
if ( conInfo && conInfo->m_notifyAllFieldsInMultiFieldChangedEvents.has_value() )
return conInfo->m_notifyAllFieldsInMultiFieldChangedEvents.value();
if ( defInfo && defInfo->m_notifyAllFieldsInMultiFieldChangedEvents.has_value() )
return defInfo->m_notifyAllFieldsInMultiFieldChangedEvents.value();
if ( sttInfo && sttInfo->m_notifyAllFieldsInMultiFieldChangedEvents.has_value() )
return sttInfo->m_notifyAllFieldsInMultiFieldChangedEvents.value();
return false;
}
@@ -576,25 +402,25 @@ bool PdmUiItem::isUiGroup() const
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
PdmUiItemInfo::LabelPosType PdmUiItem::uiLabelPosition( const QString& uiConfigName ) const
PdmUiItemInfo::LabelPosition PdmUiItem::uiLabelPosition( const QString& uiConfigName ) const
{
const PdmUiItemInfo* conInfo = configInfo( uiConfigName );
const PdmUiItemInfo* defInfo = defaultInfo();
const PdmUiItemInfo* sttInfo = m_staticItemInfo;
if ( conInfo ) return conInfo->m_labelAlignment;
if ( defInfo ) return defInfo->m_labelAlignment;
if ( sttInfo ) return sttInfo->m_labelAlignment;
if ( conInfo ) return conInfo->m_labelPosition;
if ( defInfo ) return defInfo->m_labelPosition;
if ( sttInfo ) return sttInfo->m_labelPosition;
return PdmUiItemInfo::LEFT;
return PdmUiItemInfo::LabelPosition::LEFT;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiItem::setUiLabelPosition( PdmUiItemInfo::LabelPosType alignment, const QString& uiConfigName /*= ""*/ )
void PdmUiItem::setUiLabelPosition( PdmUiItemInfo::LabelPosition position, const QString& uiConfigName /*= ""*/ )
{
m_configItemInfos[uiConfigName].m_labelAlignment = alignment;
m_configItemInfos[uiConfigName].m_labelPosition = position;
}
//--------------------------------------------------------------------------------------------------
@@ -606,9 +432,12 @@ bool PdmUiItem::isCustomContextMenuEnabled( const QString& uiConfigName /*= ""*/
const PdmUiItemInfo* defInfo = defaultInfo();
const PdmUiItemInfo* sttInfo = m_staticItemInfo;
if ( conInfo && ( conInfo->m_isCustomContextMenuEnabled != -1 ) ) return conInfo->m_isCustomContextMenuEnabled;
if ( defInfo && ( defInfo->m_isCustomContextMenuEnabled != -1 ) ) return defInfo->m_isCustomContextMenuEnabled;
if ( sttInfo && ( sttInfo->m_isCustomContextMenuEnabled != -1 ) ) return sttInfo->m_isCustomContextMenuEnabled;
if ( conInfo && conInfo->m_isCustomContextMenuEnabled.has_value() )
return conInfo->m_isCustomContextMenuEnabled.value();
if ( defInfo && defInfo->m_isCustomContextMenuEnabled.has_value() )
return defInfo->m_isCustomContextMenuEnabled.value();
if ( sttInfo && sttInfo->m_isCustomContextMenuEnabled.has_value() )
return sttInfo->m_isCustomContextMenuEnabled.value();
return false;
}
@@ -773,4 +602,96 @@ void PdmUiItem::addFieldEditor( PdmUiEditorHandle* fieldView )
m_editors.insert( fieldView );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QVariant PdmUiItem::attributeVariant( const QString& key, const QString& uiConfigName ) const
{
// Check config-specific attributes first
if ( !uiConfigName.isEmpty() )
{
auto configIt = m_attributeMaps.find( uiConfigName );
if ( configIt != m_attributeMaps.end() )
{
auto attrIt = configIt->second.find( key );
if ( attrIt != configIt->second.end() )
{
return attrIt->second;
}
}
}
// Fall back to default config ("")
auto defaultIt = m_attributeMaps.find( "" );
if ( defaultIt != m_attributeMaps.end() )
{
auto attrIt = defaultIt->second.find( key );
if ( attrIt != defaultIt->second.end() )
{
return attrIt->second;
}
}
return QVariant(); // Return invalid QVariant if not found
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::list<QString> PdmUiItem::attributeNames( const QString& uiConfigName ) const
{
std::list<QString> result;
// Start with default config attributes
auto defaultIt = m_attributeMaps.find( "" );
if ( defaultIt != m_attributeMaps.end() )
{
for ( const auto& [key, value] : defaultIt->second )
{
result.push_back( key );
}
}
// Add config-specific attributes (avoid duplicates)
if ( !uiConfigName.isEmpty() )
{
auto configIt = m_attributeMaps.find( uiConfigName );
if ( configIt != m_attributeMaps.end() )
{
for ( const auto& [key, value] : configIt->second )
{
// Check if key already exists in result
if ( std::find( result.begin(), result.end(), key ) == result.end() )
{
result.push_back( key );
}
}
}
}
return result;
}
//--------------------------------------------------------------------------------------------------
/// Validate that all attributes set on this item are in the supported set
/// Logs warnings for unsupported attributes
//--------------------------------------------------------------------------------------------------
void PdmUiItem::validateAttributes( const QString& contextName,
const std::set<QString>& supportedAttributes,
const QString& uiConfigName ) const
{
auto allAttributeNames = attributeNames( uiConfigName );
for ( const auto& key : allAttributeNames )
{
if ( supportedAttributes.find( key ) == supportedAttributes.end() )
{
CAF_PDM_LOG_WARNING(
QString( "%1: Unsupported attribute '%2' set on field. Supported attributes are: %3" )
.arg( contextName )
.arg( key )
.arg( QStringList( supportedAttributes.begin(), supportedAttributes.end() ).join( ", " ) ) );
}
}
}
} // End of namespace caf
@@ -37,199 +37,22 @@
#pragma once
#include "cafIconProvider.h"
#include "cafPdmUiFieldSpecialization.h"
#include "cafPdmOptionItemInfo.h"
#include "cafPdmUiItemInfo.h"
#include <list>
#include <map>
#include <optional>
#include <set>
#include <string>
#include <type_traits>
#include <QVariant>
namespace caf
{
//==================================================================================================
/// Class to keep (principally static) gui presentation information
/// of a data structure item (field or object) used by PdmUiItem
//==================================================================================================
class PdmUiItemInfo
{
public:
enum LabelPosType
{
LEFT,
TOP,
HIDDEN
};
PdmUiItemInfo()
: m_editorTypeName( "" )
, m_isHidden( -1 )
, m_isTreeHidden( -1 )
, m_isTreeChildrenHidden( -1 )
, m_isReadOnly( -1 )
, m_labelAlignment( LEFT )
, m_isCustomContextMenuEnabled( -1 )
, m_notifyAllFieldsInMultiFieldChangedEvents( -1 )
{
}
PdmUiItemInfo( const QString& uiName,
QString iconResourceLocation = "",
QString toolTip = "",
QString whatsThis = "",
QString extraDebugText = "" );
PdmUiItemInfo( const QString& uiName,
IconProvider iconProvider = IconProvider(),
QString toolTip = "",
QString whatsThis = "",
QString extraDebugText = "" );
std::unique_ptr<QIcon> icon() const;
const IconProvider& iconProvider() const;
private:
friend class PdmUiItem;
QString m_uiName;
IconProvider m_iconProvider;
QColor m_contentTextColor; ///< Color of a fields value text. Invalid by default. An Invalid color is not used.
QString m_toolTip;
QString m_whatsThis;
QString m_extraDebugText;
QString m_editorTypeName; ///< Use this exact type of editor to edit this UiItem
QString m_3dEditorTypeName; ///< If set, use this editor type to edit this UiItem in 3D
int m_isHidden; ///< UiItem should be hidden. -1 means not set
int m_isTreeHidden; ///< UiItem should be hidden in tree. -1 means not set
int m_isTreeChildrenHidden; ///< Children of UiItem should be hidden. -1 means not set
int m_isReadOnly; ///< UiItem should be insensitive, or read only. -1 means not set.
LabelPosType m_labelAlignment;
int m_isCustomContextMenuEnabled;
int m_notifyAllFieldsInMultiFieldChangedEvents;
};
//==================================================================================================
/// Class to keep Ui information about an option /choice in a Combobox or similar.
//==================================================================================================
class PdmOptionItemInfo
{
public:
// Template pass-through for enum types, ensuring the T type gets cast to an int before storing in the QVariant
// Note the extra dummy parameter. This ensures compilation fails for non-enum types and these variants get removed
// due to SFINAE (https://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error)
template <typename T>
PdmOptionItemInfo( const QString& anOptionUiText,
T aValue,
bool isReadOnly = false,
const IconProvider& anIcon = IconProvider(),
typename std::enable_if<std::is_enum<T>::value>::type* = 0 )
: PdmOptionItemInfo( anOptionUiText, QVariant( static_cast<int>( aValue ) ), isReadOnly, anIcon )
{
}
PdmOptionItemInfo( const QString& anOptionUiText,
const QVariant& aValue,
bool isReadOnly = false,
const IconProvider& anIcon = IconProvider() );
PdmOptionItemInfo( const QString& anOptionUiText,
caf::PdmObjectHandle* obj,
bool isReadOnly = false,
const IconProvider& anIcon = IconProvider() );
static PdmOptionItemInfo createHeader( const QString& anOptionUiText,
bool isReadOnly = false,
const IconProvider& anIcon = IconProvider() );
void setLevel( int level );
const QString optionUiText() const;
const QVariant value() const;
bool isReadOnly() const;
bool isHeading() const;
std::unique_ptr<QIcon> icon() const;
int level() const;
// Static utility methods to handle QList of PdmOptionItemInfo
// Please regard as private to the PDM system
static QStringList extractUiTexts( const QList<PdmOptionItemInfo>& optionList );
template <typename T>
static bool findValues( const QList<PdmOptionItemInfo>& optionList,
QVariant fieldValue,
std::vector<unsigned int>& foundIndexes );
private:
QString m_optionUiText;
QVariant m_value;
bool m_isReadOnly;
IconProvider m_iconProvider;
int m_level;
};
class PdmUiEditorHandle;
//--------------------------------------------------------------------------------------------------
/// Finds the indexes into the optionList that the field value(s) corresponds to.
/// In the case where the field is some kind of array, several indexes might be returned
/// The returned bool is true if all the fieldValues were found.
//--------------------------------------------------------------------------------------------------
template <typename T>
bool PdmOptionItemInfo::findValues( const QList<PdmOptionItemInfo>& optionList,
QVariant fieldValue,
std::vector<unsigned int>& foundIndexes )
{
foundIndexes.clear();
// Find this fieldvalue in the optionlist if present
// First handle lists/arrays of values
if ( fieldValue.metaType().id() == QMetaType::QVariantList )
{
QList<QVariant> valuesSelectedInField = fieldValue.toList();
if ( !valuesSelectedInField.empty() )
{
// Create a list to be able to remove items as they are matched with values
std::list<std::pair<QVariant, unsigned int>> optionVariantAndIndexPairs;
for ( int i = 0; i < optionList.size(); ++i )
{
optionVariantAndIndexPairs.push_back( std::make_pair( optionList[i].value(), i ) );
}
for ( int i = 0; i < valuesSelectedInField.size(); ++i )
{
std::list<std::pair<QVariant, unsigned int>>::iterator it;
for ( it = optionVariantAndIndexPairs.begin(); it != optionVariantAndIndexPairs.end(); ++it )
{
if ( PdmUiFieldSpecialization<T>::isDataElementEqual( valuesSelectedInField[i], it->first ) )
{
foundIndexes.push_back( it->second );
// Assuming that one option is referenced only once, the option is erased. Then break
// out of the inner loop, as this operation can be costly for fields with many options and many
// values
optionVariantAndIndexPairs.erase( it );
break;
}
}
}
}
return ( static_cast<size_t>( valuesSelectedInField.size() ) <= foundIndexes.size() );
}
else // Then handle single value fields
{
for ( unsigned int opIdx = 0; opIdx < static_cast<unsigned int>( optionList.size() ); ++opIdx )
{
if ( PdmUiFieldSpecialization<T>::isDataElementEqual( optionList[opIdx].value(), fieldValue ) )
{
foundIndexes.push_back( opIdx );
break;
}
}
return ( !foundIndexes.empty() );
}
}
//==================================================================================================
/// Base class for all datastructure items (fields or objects) to make them have information on
/// how to display them in the GUI. All the information can have a static variant valid for all
@@ -279,8 +102,8 @@ public:
bool notifyAllFieldsInMultiFieldChangedEvents( const QString& uiConfigName = "" ) const;
void setNotifyAllFieldsInMultiFieldChangedEvents( bool enable, const QString& uiConfigName = "" );
PdmUiItemInfo::LabelPosType uiLabelPosition( const QString& uiConfigName = "" ) const;
void setUiLabelPosition( PdmUiItemInfo::LabelPosType alignment, const QString& uiConfigName = "" );
PdmUiItemInfo::LabelPosition uiLabelPosition( const QString& uiConfigName = "" ) const;
void setUiLabelPosition( PdmUiItemInfo::LabelPosition position, const QString& uiConfigName = "" );
bool isCustomContextMenuEnabled( const QString& uiConfigName = "" ) const;
void setCustomContextMenuEnabled( bool enableCustomContextMenu, const QString& uiConfigName = "" );
@@ -293,6 +116,78 @@ public:
virtual bool isUiGroup() const;
// Map-based attribute system
/// Sets an attribute value for this UI item.
///
/// Attributes provide a flexible way to configure UI editor behavior without
/// modifying the editor classes themselves. Each attribute is stored as a key-value
/// pair and can be retrieved later by editors during configuration.
///
/// String Type Handling:
/// ---------------------
/// The method automatically converts C-style strings to QString for Qt integration:
/// - String literals: "text" or char[N] arrays
/// - String pointers: const char* or char*
/// All other types are stored directly in QVariant.
///
/// Usage Examples:
/// ---------------
/// @code
/// // String literal (automatically converted to QString)
/// field.uiCapability()->setAttribute("dateFormat", "yyyy-MM-dd");
///
/// // Lambda/function (stored in QVariant)
/// field.uiCapability()->setAttribute("callback", myCallbackFunction);
///
/// // Numeric value (stored in QVariant)
/// field.uiCapability()->setAttribute("maxLength", 100);
///
/// @endcode
template <typename T>
void setAttribute( const QString& key, const T& value, const QString& uiConfigName = "" )
{
// Decay type removes references, const, and volatile qualifiers
// This helps us identify the true underlying type
using DecayedT = std::decay_t<T>;
// Check if value is a C-style string pointer (const char* or char*)
constexpr bool isCStringPointer = std::is_same_v<DecayedT, const char*> || std::is_same_v<DecayedT, char*>;
// Check if value is a character array (string literal like "text" or char[75])
constexpr bool isCharArray = std::is_array_v<T> && std::is_same_v<std::remove_extent_t<T>, char>;
if constexpr ( isCStringPointer || isCharArray )
{
// Convert C-style strings to QString for proper Qt string handling
m_attributeMaps[uiConfigName][key] = QString( value );
}
else
{
// Store all other types (int, double, function pointers, etc.) in QVariant
// QVariant handles type-safe storage and retrieval of various types
m_attributeMaps[uiConfigName][key] = QVariant::fromValue( value );
}
}
template <typename T>
std::optional<T> attribute( const QString& key, const QString& uiConfigName = "" ) const
{
QVariant value = attributeVariant( key, uiConfigName );
if ( value.isValid() && value.canConvert<T>() )
{
return value.value<T>();
}
return std::nullopt;
}
std::list<QString> attributeNames( const QString& uiConfigName = "" ) const;
// Helper function to validate attributes against a supported set
void validateAttributes( const QString& contextName,
const std::set<QString>& supportedAttributes,
const QString& uiConfigName = "" ) const;
/// Intended to be called when fields in an object has been changed
void updateConnectedEditors() const;
void scheduleUpdateConnectedEditors() const;
@@ -324,6 +219,9 @@ public: // Pdm-Private only
protected:
std::set<PdmUiEditorHandle*> m_editors;
private:
QVariant attributeVariant( const QString& key, const QString& uiConfigName = "" ) const;
private:
const PdmUiItemInfo* defaultInfo() const;
const PdmUiItemInfo* configInfo( const QString& uiConfigName ) const;
@@ -331,6 +229,9 @@ private:
PdmUiItemInfo* m_staticItemInfo;
std::map<QString, PdmUiItemInfo> m_configItemInfos;
// Map-based attributes: uiConfigName -> (attributeKey -> value)
std::map<QString, std::map<QString, QVariant>> m_attributeMaps;
static bool sm_showExtraDebugText;
};
@@ -0,0 +1,91 @@
//##################################################################################################
//
// 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.
//
//##################################################################################################
#include "cafPdmUiItemInfo.h"
namespace caf
{
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
PdmUiItemInfo::PdmUiItemInfo( const QString& uiName,
IconProvider iconProvider,
QString toolTip,
QString whatsThis,
QString extraDebugText )
: m_uiName( uiName )
, m_iconProvider( iconProvider )
, m_toolTip( toolTip )
, m_whatsThis( whatsThis )
, m_extraDebugText( extraDebugText )
, m_labelPosition( LabelPosition::LEFT )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
PdmUiItemInfo::PdmUiItemInfo( const QString& uiName,
QString iconResourceLocation,
QString toolTip,
QString whatsThis,
QString extraDebugText )
: m_uiName( uiName )
, m_iconProvider( iconResourceLocation )
, m_toolTip( toolTip )
, m_whatsThis( whatsThis )
, m_extraDebugText( extraDebugText )
, m_labelPosition( LabelPosition::LEFT )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::unique_ptr<QIcon> PdmUiItemInfo::icon() const
{
return m_iconProvider.icon();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const IconProvider& PdmUiItemInfo::iconProvider() const
{
return m_iconProvider;
}
} // End of namespace caf
@@ -0,0 +1,104 @@
//##################################################################################################
//
// 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.
//
//##################################################################################################
#pragma once
#include "cafIconProvider.h"
#include <memory>
#include <optional>
class QIcon;
namespace caf
{
//==================================================================================================
/// Class to keep (principally static) gui presentation information
/// of a data structure item (field or object) used by PdmUiItem
//==================================================================================================
class PdmUiItemInfo
{
public:
enum class LabelPosition
{
LEFT,
TOP,
HIDDEN
};
PdmUiItemInfo()
: m_editorTypeName( "" )
, m_labelPosition( LabelPosition::LEFT )
{
}
PdmUiItemInfo( const QString& uiName,
QString iconResourceLocation = "",
QString toolTip = "",
QString whatsThis = "",
QString extraDebugText = "" );
PdmUiItemInfo( const QString& uiName,
IconProvider iconProvider = IconProvider(),
QString toolTip = "",
QString whatsThis = "",
QString extraDebugText = "" );
std::unique_ptr<QIcon> icon() const;
const IconProvider& iconProvider() const;
private:
friend class PdmUiItem;
QString m_uiName;
IconProvider m_iconProvider;
QColor m_contentTextColor;
QString m_toolTip;
QString m_whatsThis;
QString m_extraDebugText;
QString m_editorTypeName;
QString m_3dEditorTypeName;
LabelPosition m_labelPosition;
std::optional<bool> m_isHidden;
std::optional<bool> m_isTreeHidden;
std::optional<bool> m_isTreeChildrenHidden;
std::optional<bool> m_isReadOnly;
std::optional<bool> m_isCustomContextMenuEnabled;
std::optional<bool> m_notifyAllFieldsInMultiFieldChangedEvents;
};
} // End of namespace caf
@@ -431,7 +431,7 @@ void PdmUiOrdering::nrOfColumnsRequiredForItem( const FieldAndLayout& fieldAndLa
{
*fieldColumnsRequired = 1;
*labelColumnsRequired = 0;
if ( uiItem->uiLabelPosition() == PdmUiItemInfo::LEFT )
if ( uiItem->uiLabelPosition() == PdmUiItemInfo::LabelPosition::LEFT )
{
*labelColumnsRequired = 1;
if ( layoutOption.leftLabelColumnSpan != MAX_COLUMN_SPAN )