Add framework support for editor auto values

Add support for a field to be linked to a value updated by code outside the object itself. Mark the linked field by using a background color and icons for linked/unlinked state.
The auto value states is set as attributes in the project xml file. 
Add reference implementation in cafTestApplication, see Fwk/AppFwk/cafTests/cafTestApplication/MainWindow.cpp

* Tree View Editor: Avoid sending notification if selection is unchanged
* Use std++17 in test solution
* Move icons to icon factory
* add support for creating QIcon from SVG text string
This commit is contained in:
Magne Sjaastad
2022-09-02 13:20:52 +02:00
committed by GitHub
parent 30c3fe3a5c
commit e97a476d85
24 changed files with 979 additions and 183 deletions

View File

@@ -1,5 +1,9 @@
#pragma once
#include <vector>
class QString;
namespace caf
{
class PdmFieldCapability
@@ -7,6 +11,9 @@ class PdmFieldCapability
public:
PdmFieldCapability() {}
virtual ~PdmFieldCapability() {}
virtual std::vector<std::pair<QString, QString>> attributes() const { return {}; }
virtual void setAttributes( const std::vector<std::pair<QString, QString>>& attributes ) {}
};
} // End of namespace caf

View File

@@ -102,6 +102,21 @@ bool PdmFieldHandle::hasPtrReferencedObjects()
return ( ptrReffedObjs.size() > 0 );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<caf::PdmFieldCapability*> PdmFieldHandle::capabilities() const
{
std::vector<caf::PdmFieldCapability*> allCapabilities;
for ( const auto& cap : m_capabilities )
{
allCapabilities.push_back( cap.first );
}
return allCapabilities;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@@ -46,6 +46,8 @@ public:
m_capabilities.push_back( std::make_pair( capability, takeOwnership ) );
}
std::vector<caf::PdmFieldCapability*> capabilities() const;
template <typename CapabilityType>
CapabilityType* capability();
template <typename CapabilityType>

View File

@@ -155,16 +155,11 @@ QVariant PdmFieldUiCap<FieldType>::uiValue() const
return QVariant( returnList );
}
}
else
{
if ( indexesToFoundOptions.size() == 1 )
return QVariant( indexesToFoundOptions.front() );
else
return QVariant( -1 ); // Return -1 if not found instead of assert. Should result in clearing the selection
}
CAF_ASSERT( false );
return uiBasedQVariant;
if ( indexesToFoundOptions.size() == 1 ) return QVariant( indexesToFoundOptions.front() );
// Return -1 if not found, expected result in clearing the selection
return QVariant( -1 );
}
else
{
@@ -217,7 +212,7 @@ QList<PdmOptionItemInfo> PdmFieldUiCap<FieldType>::valueOptions() const
foundIndexes );
// If not all are found, we have to add the missing to the list, to be able to show it
// This will only work if the field data type (or elemnt type for containers) is supported by
// This will only work if the field data type (or element type for containers) is supported by
// QVariant.toString(). Custom classes don't
if ( !foundAllFieldValues )

View File

@@ -13,6 +13,8 @@ namespace caf
//--------------------------------------------------------------------------------------------------
PdmUiFieldHandle::PdmUiFieldHandle( PdmFieldHandle* owner, bool giveOwnership )
: m_isAutoAddingOptionFromValue( true )
, m_useAutoValue( false )
, m_isAutoValueSupported( false )
{
m_owner = owner;
owner->addCapability( this, giveOwnership );
@@ -121,6 +123,122 @@ void PdmUiFieldHandle::setAutoAddingOptionFromValue( bool isAddingValue )
m_isAutoAddingOptionFromValue = isAddingValue;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiFieldHandle::enableAndSetAutoValue( const QVariant& autoValue )
{
setAutoValue( autoValue );
enableAutoValue( true );
m_isAutoValueSupported = true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiFieldHandle::setAutoValue( const QVariant& autoValue )
{
m_autoValue = autoValue;
if ( m_useAutoValue )
{
setValueFromUiEditor( m_autoValue, false );
updateConnectedEditors();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QVariant PdmUiFieldHandle::autoValue() const
{
return m_autoValue;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiFieldHandle::enableAutoValue( bool enable )
{
m_useAutoValue = enable;
if ( m_useAutoValue )
{
setValueFromUiEditor( m_autoValue, false );
updateConnectedEditors();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool PdmUiFieldHandle::isAutoValueEnabled() const
{
return m_useAutoValue;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiFieldHandle::enableAutoValueSupport( bool enable )
{
m_isAutoValueSupported = enable;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool PdmUiFieldHandle::isAutoValueSupported() const
{
return m_isAutoValueSupported;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<std::pair<QString, QString>> PdmUiFieldHandle::attributes() const
{
std::vector<std::pair<QString, QString>> attr;
if ( m_useAutoValue )
{
attr.push_back( { "autoValueEnabled", "true" } );
}
if ( m_isAutoValueSupported )
{
attr.push_back( { "autoValueSupported", "true" } );
}
return attr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiFieldHandle::setAttributes( const std::vector<std::pair<QString, QString>>& attributes )
{
for ( auto [key, valueString] : attributes )
{
valueString = valueString.toUpper();
if ( key == "autoValueEnabled" )
{
if ( valueString == "TRUE" )
{
enableAutoValue( true );
}
}
else if ( key == "autoValueSupported" )
{
if ( valueString == "TRUE" )
{
enableAutoValueSupport( true );
}
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@@ -27,6 +27,17 @@ public:
bool isAutoAddingOptionFromValue() const;
void setAutoAddingOptionFromValue( bool isAddingValue );
void enableAndSetAutoValue( const QVariant& autoValue );
void setAutoValue( const QVariant& autoValue );
QVariant autoValue() const;
void enableAutoValue( bool enable );
bool isAutoValueEnabled() const;
void enableAutoValueSupport( bool enable );
bool isAutoValueSupported() const;
std::vector<std::pair<QString, QString>> attributes() const override;
void setAttributes( const std::vector<std::pair<QString, QString>>& attributes ) override;
private:
friend class PdmUiCommandSystemProxy;
friend class CmdFieldChangeExec;
@@ -38,6 +49,10 @@ private:
private:
PdmFieldHandle* m_owner;
bool m_isAutoAddingOptionFromValue;
QVariant m_autoValue;
bool m_useAutoValue;
bool m_isAutoValueSupported;
};
} // End of namespace caf

View File

@@ -82,7 +82,7 @@ void SelectionManager::selectedItems( std::vector<PdmUiItem*>& items, int select
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void SelectionManager::setSelectedItems( const std::vector<PdmUiItem*>& items )
bool SelectionManager::setSelectedItems( const std::vector<PdmUiItem*>& items )
{
std::map<int, std::vector<std::pair<PdmPointer<PdmObjectHandle>, PdmUiItem*>>> newCompleteSelectionMap;
@@ -96,7 +96,10 @@ void SelectionManager::setSelectedItems( const std::vector<PdmUiItem*>& items )
{
m_selectionPrLevel = newCompleteSelectionMap;
notifySelectionChanged( changedLevels );
return true;
}
return false;
}
//--------------------------------------------------------------------------------------------------

View File

@@ -74,7 +74,7 @@ public:
void setSelectedItem( PdmUiItem* item );
void setSelectedItemAtLevel( PdmUiItem* item, int selectionLevel );
void setSelectedItems( const std::vector<PdmUiItem*>& items );
bool setSelectedItems( const std::vector<PdmUiItem*>& items );
void setSelectedItemsAtLevel( const std::vector<PdmUiItem*>& items, int selectionLevel = 0 );
struct SelectionItem

View File

@@ -57,6 +57,22 @@ void PdmXmlObjectHandle::readFields( QXmlStreamReader& xmlStream, PdmObjectFacto
PdmFieldHandle* fieldHandle = m_owner->findField( name );
if ( fieldHandle && fieldHandle->xmlCapability() )
{
auto xmlAttributes = xmlStream.attributes();
if ( !xmlAttributes.isEmpty() )
{
std::vector<std::pair<QString, QString>> fieldAttributes;
for ( const auto& xmlAttr : xmlAttributes )
{
fieldAttributes.emplace_back( xmlAttr.name().toString(), xmlAttr.value().toString() );
}
for ( auto capability : fieldHandle->capabilities() )
{
capability->setAttributes( fieldAttributes );
}
}
PdmXmlFieldHandle* xmlFieldHandle = fieldHandle->xmlCapability();
bool readable = xmlFieldHandle->isIOReadable();
if ( isCopyOperation && !xmlFieldHandle->isCopyable() )
@@ -66,8 +82,8 @@ void PdmXmlObjectHandle::readFields( QXmlStreamReader& xmlStream, PdmObjectFacto
if ( readable )
{
// readFieldData assumes that the xmlStream points to first token of field content.
// After reading, the xmlStream is supposed to point to the first token after the field content.
// (typically an "endElement")
// After reading, the xmlStream is supposed to point to the first token after the field
// content. (typically an "endElement")
QXmlStreamReader::TokenType tt;
tt = xmlStream.readNext();
xmlFieldHandle->readFieldData( xmlStream, objectFactory );
@@ -82,9 +98,10 @@ void PdmXmlObjectHandle::readFields( QXmlStreamReader& xmlStream, PdmObjectFacto
// Debug text is commented out, as this code is relatively often reached. Consider a new logging
// concept to receive this information
//
// std::cout << "Line " << xmlStream.lineNumber() << ": Warning: Could not find a field with name "
// << name.toLatin1().data() << " in the current object : " << classKeyword().toLatin1().data() <<
// std::endl;
// std::cout << "Line " << xmlStream.lineNumber() << ": Warning: Could not find a field with
// name "
// << name.toLatin1().data() << " in the current object : " << classKeyword().toLatin1().data()
// << std::endl;
xmlStream.skipCurrentElement();
}
@@ -120,16 +137,27 @@ void PdmXmlObjectHandle::writeFields( QXmlStreamWriter& xmlStream ) const
{
std::vector<PdmFieldHandle*> fields;
m_owner->fields( fields );
for ( size_t it = 0; it < fields.size(); ++it )
for ( const auto& fieldHandle : fields )
{
const PdmXmlFieldHandle* field = fields[it]->xmlCapability();
const PdmXmlFieldHandle* field = fieldHandle->xmlCapability();
if ( field && field->isIOWritable() )
{
QString keyword = field->fieldHandle()->keyword();
CAF_ASSERT( PdmXmlObjectHandle::isValidXmlElementName( keyword ) );
xmlStream.writeStartElement( "", keyword );
for ( auto cap : fieldHandle->capabilities() )
{
auto attributes = cap->attributes();
for ( const auto& [key, value] : attributes )
{
xmlStream.writeAttribute( key, value );
}
}
field->writeFieldData( xmlStream );
xmlStream.writeEndElement();
}
}