#8966 Improve performance when changing multiple field values

This commit is contained in:
Magne Sjaastad 2022-05-26 17:25:17 +02:00
parent 3545d16fbb
commit b17e3813df
11 changed files with 191 additions and 128 deletions

View File

@ -121,6 +121,25 @@ void RimSummaryCurveCollection::loadDataAndUpdate( bool updateParentPlot )
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryCurveCollection::onChildrenUpdated( caf::PdmChildArrayFieldHandle* childArray,
std::vector<caf::PdmObjectHandle*>& updatedObjects )
{
if ( childArray == &m_curves )
{
for ( RimSummaryCurve* curve : m_curves )
{
curve->updateCurveAppearance();
}
RimSummaryPlot* parentPlot;
firstAncestorOrThisOfTypeAsserted( parentPlot );
parentPlot->plotWidget()->scheduleReplot();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -99,6 +99,9 @@ private:
void onChildDeleted( caf::PdmChildArrayFieldHandle* childArray,
std::vector<caf::PdmObjectHandle*>& referringObjects ) override;
void onChildrenUpdated( caf::PdmChildArrayFieldHandle* childArray,
std::vector<caf::PdmObjectHandle*>& updatedObjects ) override;
private:
friend class RimSummaryCrossPlot;
friend class RimSummaryPlot;

View File

@ -41,39 +41,38 @@
namespace caf
{
CAF_PDM_SOURCE_INIT( CmdFieldChangeExecData, "CmdFieldChangeExecData" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString CmdFieldChangeExec::name()
{
PdmFieldHandle* field =
PdmReferenceHelper::fieldFromReference( m_commandData->m_rootObject, m_commandData->m_pathToField );
if ( field )
if ( !m_commandData->m_pathToFields.empty() )
{
QString fieldText;
PdmUiFieldHandle* uiFieldHandle = field->uiCapability();
if ( uiFieldHandle )
PdmFieldHandle* field =
PdmReferenceHelper::fieldFromReference( m_commandData->m_rootObject, m_commandData->m_pathToFields.front() );
if ( field )
{
fieldText = QString( "Change field '%1'" ).arg( uiFieldHandle->uiName() );
}
QString fieldText;
if ( field->ownerObject() )
{
PdmUiObjectHandle* uiObjHandle = uiObj( field->ownerObject() );
if ( uiObjHandle )
PdmUiFieldHandle* uiFieldHandle = field->uiCapability();
if ( uiFieldHandle )
{
fieldText += QString( " in '%1'" ).arg( uiObjHandle->uiName() );
fieldText = QString( "Change field '%1'" ).arg( uiFieldHandle->uiName() );
}
if ( field->ownerObject() )
{
PdmUiObjectHandle* uiObjHandle = uiObj( field->ownerObject() );
if ( uiObjHandle )
{
fieldText += QString( " in '%1'" ).arg( uiObjHandle->uiName() );
}
}
return fieldText;
}
return fieldText;
}
else
{
return m_commandData->classKeyword();
}
return "Field Changed";
}
//--------------------------------------------------------------------------------------------------
@ -81,53 +80,67 @@ QString CmdFieldChangeExec::name()
//--------------------------------------------------------------------------------------------------
void CmdFieldChangeExec::redo()
{
PdmFieldHandle* field =
PdmReferenceHelper::fieldFromReference( m_commandData->m_rootObject, m_commandData->m_pathToField );
if ( !field )
m_commandData->m_undoFieldValueSerialized.resize( m_commandData->m_pathToFields.size() );
for ( size_t i = 0; i < m_commandData->m_pathToFields.size(); i++ )
{
CAF_ASSERT( false );
return;
}
auto fieldTextPath = m_commandData->m_pathToFields[i];
PdmUiFieldHandle* uiFieldHandle = field->uiCapability();
PdmXmlFieldHandle* xmlFieldHandle = field->xmlCapability();
if ( uiFieldHandle && xmlFieldHandle )
{
if ( m_commandData->m_redoFieldValueSerialized.isEmpty() )
PdmFieldHandle* field = PdmReferenceHelper::fieldFromReference( m_commandData->m_rootObject, fieldTextPath );
if ( !field ) continue;
PdmUiFieldHandle* uiFieldHandle = field->uiCapability();
PdmXmlFieldHandle* xmlFieldHandle = field->xmlCapability();
if ( uiFieldHandle && xmlFieldHandle )
{
// We end up here only when the user actually has done something in the actual living Gui editor.
bool isLastField = ( i == m_commandData->m_pathToFields.size() - 1 );
if ( m_commandData->m_undoFieldValueSerialized[i].isEmpty() )
{
QXmlStreamWriter xmlStream( &m_commandData->m_undoFieldValueSerialized );
writeFieldDataToValidXmlDocument( xmlStream, xmlFieldHandle );
// We end up here only when the user actually has done something in the actual living Gui editor.
{
QXmlStreamWriter xmlStream( &m_commandData->m_undoFieldValueSerialized[i] );
writeFieldDataToValidXmlDocument( xmlStream, xmlFieldHandle );
}
// This function will notify field change, no need to explicitly call notification
// The ui value might be an index into the option entry cache, so we need to set the value
// and be aware of the option entries, and then serialize the actual field value we ended up with.
uiFieldHandle->setValueFromUiEditor( m_commandData->m_newUiValue, isLastField );
if ( m_commandData->m_redoFieldValueSerialized.isEmpty() )
{
QXmlStreamWriter xmlStream( &m_commandData->m_redoFieldValueSerialized );
writeFieldDataToValidXmlDocument( xmlStream, xmlFieldHandle );
}
}
// This function will notify field change, no need to explicitly call notification
// The ui value might be an index into the option entry cache, so we need to set the value
// and be aware of the option entries, and then serialize the actual field value we ended up with.
uiFieldHandle->setValueFromUiEditor( m_commandData->m_newUiValue );
else
{
QXmlStreamWriter xmlStream( &m_commandData->m_redoFieldValueSerialized );
writeFieldDataToValidXmlDocument( xmlStream, xmlFieldHandle );
QVariant oldFieldData = uiFieldHandle->toUiBasedQVariant();
QXmlStreamReader xmlStream( m_commandData->m_redoFieldValueSerialized );
readFieldValueFromValidXmlDocument( xmlStream, xmlFieldHandle );
QVariant newFieldData = uiFieldHandle->toUiBasedQVariant();
// New data is present in field, notify data changed
if ( isLastField )
{
uiFieldHandle->notifyFieldChanged( oldFieldData, newFieldData );
if ( m_notificationCenter )
m_notificationCenter->notifyObserversOfDataChange( field->ownerObject() );
}
}
}
else
{
QVariant oldFieldData = uiFieldHandle->toUiBasedQVariant();
QXmlStreamReader xmlStream( m_commandData->m_redoFieldValueSerialized );
readFieldValueFromValidXmlDocument( xmlStream, xmlFieldHandle );
QVariant newFieldData = uiFieldHandle->toUiBasedQVariant();
// New data is present in field, notify data changed
uiFieldHandle->notifyFieldChanged( oldFieldData, newFieldData );
}
}
if ( m_notificationCenter ) m_notificationCenter->notifyObserversOfDataChange( field->ownerObject() );
if ( m_commandData->m_ownerOfChildArrayField && m_commandData->m_childArrayFieldHandle )
{
std::vector<caf::PdmObjectHandle*> objs;
m_commandData->m_ownerOfChildArrayField->onChildrenUpdated( m_commandData->m_childArrayFieldHandle, objs );
}
}
//--------------------------------------------------------------------------------------------------
@ -135,30 +148,40 @@ void CmdFieldChangeExec::redo()
//--------------------------------------------------------------------------------------------------
void CmdFieldChangeExec::undo()
{
PdmFieldHandle* field =
PdmReferenceHelper::fieldFromReference( m_commandData->m_rootObject, m_commandData->m_pathToField );
if ( !field )
for ( size_t i = 0; i < m_commandData->m_pathToFields.size(); i++ )
{
CAF_ASSERT( false );
return;
auto fieldTextPath = m_commandData->m_pathToFields[i];
PdmFieldHandle* field = PdmReferenceHelper::fieldFromReference( m_commandData->m_rootObject, fieldTextPath );
if ( !field ) continue;
PdmUiFieldHandle* uiFieldHandle = field->uiCapability();
PdmXmlFieldHandle* xmlFieldHandle = field->xmlCapability();
if ( uiFieldHandle && xmlFieldHandle )
{
bool isLastField = ( i == m_commandData->m_pathToFields.size() - 1 );
QXmlStreamReader xmlStream( m_commandData->m_undoFieldValueSerialized[i] );
QVariant oldFieldData = uiFieldHandle->toUiBasedQVariant();
readFieldValueFromValidXmlDocument( xmlStream, xmlFieldHandle );
QVariant newFieldData = uiFieldHandle->toUiBasedQVariant();
// New data is present in field, notify data changed
if ( isLastField )
{
uiFieldHandle->notifyFieldChanged( oldFieldData, newFieldData );
if ( m_notificationCenter ) m_notificationCenter->notifyObserversOfDataChange( field->ownerObject() );
}
}
}
PdmUiFieldHandle* uiFieldHandle = field->uiCapability();
PdmXmlFieldHandle* xmlFieldHandle = field->xmlCapability();
if ( uiFieldHandle && xmlFieldHandle )
if ( m_commandData->m_ownerOfChildArrayField && m_commandData->m_childArrayFieldHandle )
{
QXmlStreamReader xmlStream( m_commandData->m_undoFieldValueSerialized );
QVariant oldFieldData = uiFieldHandle->toUiBasedQVariant();
readFieldValueFromValidXmlDocument( xmlStream, xmlFieldHandle );
QVariant newFieldData = uiFieldHandle->toUiBasedQVariant();
// New data is present in field, notify data changed
uiFieldHandle->notifyFieldChanged( oldFieldData, newFieldData );
std::vector<caf::PdmObjectHandle*> objs;
m_commandData->m_ownerOfChildArrayField->onChildrenUpdated( m_commandData->m_childArrayFieldHandle, objs );
}
if ( m_notificationCenter ) m_notificationCenter->notifyObserversOfDataChange( field->ownerObject() );
}
//--------------------------------------------------------------------------------------------------

View File

@ -40,35 +40,32 @@
#include "cafPdmField.h"
#include "cafPdmObject.h"
#include <vector>
namespace caf
{
class PdmChildArrayFieldHandle;
//==================================================================================================
///
//==================================================================================================
class CmdFieldChangeExecData : public PdmObject
class CmdFieldChangeExecData
{
CAF_PDM_HEADER_INIT;
public:
CmdFieldChangeExecData()
: m_rootObject( nullptr )
, m_childArrayFieldHandle( nullptr )
, m_ownerOfChildArrayField( nullptr )
{
CAF_PDM_InitObject( "CmdFieldChangeExecData uiName",
"",
"CmdFieldChangeExecData tooltip",
"CmdFieldChangeExecData whatsthis" );
CAF_PDM_InitField( &m_pathToField, "PathToField", QString(), "PathToField", "", "PathToField tooltip", "PathToField whatsthis" );
}
caf::PdmPointer<PdmObjectHandle> m_rootObject;
PdmChildArrayFieldHandle* m_childArrayFieldHandle;
PdmObjectHandle* m_ownerOfChildArrayField;
PdmField<QString> m_pathToField;
QVariant m_newUiValue; // QVariant coming from the UI
std::vector<QString> m_pathToFields;
std::vector<QString> m_undoFieldValueSerialized;
QString m_undoFieldValueSerialized;
QString m_redoFieldValueSerialized;
QVariant m_newUiValue;
QString m_redoFieldValueSerialized;
};
//==================================================================================================

View File

@ -40,10 +40,10 @@
#include "cafCmdExecuteCommand.h"
#include "cafCmdFeatureManager.h"
#include "cafCmdFieldChangeExec.h"
#include "cafPdmChildArrayField.h"
#include "cafPdmFieldHandle.h"
#include "cafPdmObjectHandle.h"
#include "cafPdmUiObjectHandle.h"
#include "cafSelectionManager.h"
#include <QMenu>
@ -71,45 +71,64 @@ void CmdUiCommandSystemImpl::fieldChangedCommand( const std::vector<PdmFieldHand
std::vector<CmdExecuteCommand*> commands;
for ( size_t i = 0; i < fieldsToUpdate.size(); i++ )
PdmChildArrayFieldHandle* childArrayFieldHandle = nullptr;
PdmObjectHandle* ownerOfChildArrayField = nullptr;
PdmObjectHandle* rootObjHandle = nullptr;
auto firstField = fieldsToUpdate.front();
if ( firstField )
{
// Find the first childArrayField by traversing parent field and objects. Usually, the childArrayField is
// the parent, but in some cases when we change fields in a sub-object of the object we need to traverse
// more levels
ownerOfChildArrayField = firstField->ownerObject();
while ( ownerOfChildArrayField )
{
if ( ownerOfChildArrayField->parentField() )
{
childArrayFieldHandle =
dynamic_cast<caf::PdmChildArrayFieldHandle*>( ownerOfChildArrayField->parentField() );
ownerOfChildArrayField = ownerOfChildArrayField->parentField()->ownerObject();
if ( childArrayFieldHandle && ownerOfChildArrayField ) break;
}
else
{
ownerOfChildArrayField = nullptr;
}
}
rootObjHandle = PdmReferenceHelper::findRoot( firstField );
}
std::vector<QString> pathsToFields;
for ( caf::PdmFieldHandle* field : fieldsToUpdate )
{
PdmFieldHandle* field = fieldsToUpdate[i];
PdmUiFieldHandle* uiFieldHandle = field->uiCapability();
if ( uiFieldHandle )
{
QVariant fieldCurrentUiValue = uiFieldHandle->uiValue();
if ( fieldCurrentUiValue != newUiValue )
{
PdmObjectHandle* rootObjHandle = PdmReferenceHelper::findRoot( field );
QString reference = PdmReferenceHelper::referenceFromRootToField( rootObjHandle, field );
if ( reference.isEmpty() )
QString pathToField = PdmReferenceHelper::referenceFromRootToField( rootObjHandle, field );
if ( !pathToField.isEmpty() )
{
CAF_ASSERT( false );
return;
pathsToFields.push_back( pathToField );
}
CmdFieldChangeExec* fieldChangeExec =
new CmdFieldChangeExec( SelectionManager::instance()->notificationCenter() );
fieldChangeExec->commandData()->m_newUiValue = newUiValue;
fieldChangeExec->commandData()->m_pathToField = reference;
fieldChangeExec->commandData()->m_rootObject = rootObjHandle;
commands.push_back( fieldChangeExec );
}
}
}
if ( commands.size() == 1 )
{
CmdExecCommandManager::instance()->processExecuteCommand( commands[0] );
}
else
{
CmdExecCommandManager::instance()->processExecuteCommandsAsMacro( commands );
}
auto* fieldChangeExec = new CmdFieldChangeExec( SelectionManager::instance()->notificationCenter() );
fieldChangeExec->commandData()->m_newUiValue = newUiValue;
fieldChangeExec->commandData()->m_pathToFields = pathsToFields;
fieldChangeExec->commandData()->m_rootObject = rootObjHandle;
fieldChangeExec->commandData()->m_ownerOfChildArrayField = ownerOfChildArrayField;
fieldChangeExec->commandData()->m_childArrayFieldHandle = childArrayFieldHandle;
CmdExecCommandManager::instance()->processExecuteCommand( fieldChangeExec );
}
//--------------------------------------------------------------------------------------------------

View File

@ -107,6 +107,8 @@ public:
std::vector<caf::PdmObjectHandle*>& referringObjects );
virtual void onChildAdded( caf::PdmFieldHandle* containerForNewObject ){};
virtual void onChildrenUpdated( PdmChildArrayFieldHandle* childArray,
std::vector<caf::PdmObjectHandle*>& updatedObjects ){};
virtual void
handleDroppedMimeData( const QMimeData* data, Qt::DropAction action, caf::PdmFieldHandle* destinationField ){};

View File

@ -17,7 +17,7 @@ public:
// Gui generalized interface
public:
QVariant uiValue() const override;
void setValueFromUiEditor( const QVariant& uiValue ) override;
void setValueFromUiEditor( const QVariant& uiValue, bool notifyFieldChanged ) override;
QList<PdmOptionItemInfo> valueOptions( bool* useOptionsOnly ) const override;
QVariant toUiBasedQVariant() const override;
@ -48,7 +48,7 @@ public:
// Gui generalized interface
public:
QVariant uiValue() const override { return QVariant(); }
void setValueFromUiEditor( const QVariant& uiValue ) override {}
void setValueFromUiEditor( const QVariant& uiValue, bool notifyFieldChanged ) override {}
QList<PdmOptionItemInfo> valueOptions( bool* useOptionsOnly ) const override { return QList<PdmOptionItemInfo>(); }
QVariant toUiBasedQVariant() const override { return QVariant(); }
@ -71,7 +71,7 @@ public:
// Gui generalized interface
public:
QVariant uiValue() const override { return QVariant(); }
void setValueFromUiEditor( const QVariant& uiValue ) override {}
void setValueFromUiEditor( const QVariant& uiValue, bool notifyFieldChanged ) override {}
QList<PdmOptionItemInfo> valueOptions( bool* useOptionsOnly ) const override { return QList<PdmOptionItemInfo>(); }
QVariant toUiBasedQVariant() const override { return QVariant(); }

View File

@ -14,7 +14,7 @@ namespace caf
//--------------------------------------------------------------------------------------------------
template <typename FieldType>
void PdmFieldUiCap<FieldType>::setValueFromUiEditor( const QVariant& uiValue )
void PdmFieldUiCap<FieldType>::setValueFromUiEditor( const QVariant& uiValue, bool notifyFieldChanged )
{
QVariant oldUiBasedQVariant = toUiBasedQVariant();
@ -100,7 +100,7 @@ void PdmFieldUiCap<FieldType>::setValueFromUiEditor( const QVariant& uiValue )
QVariant newUiBasedQVariant = toUiBasedQVariant();
this->notifyFieldChanged( oldUiBasedQVariant, newUiBasedQVariant );
if ( notifyFieldChanged ) this->notifyFieldChanged( oldUiBasedQVariant, newUiBasedQVariant );
}
//--------------------------------------------------------------------------------------------------

View File

@ -114,7 +114,7 @@ void PdmUiCommandSystemProxy::setUiValueToField( PdmUiFieldHandle* uiFieldHandle
for ( auto fieldHandle : fieldsToUpdate )
{
fieldHandle->uiCapability()->setValueFromUiEditor( newUiValue );
fieldHandle->uiCapability()->setValueFromUiEditor( newUiValue, true );
}
}
}

View File

@ -124,7 +124,7 @@ void PdmUiFieldHandle::setAutoAddingOptionFromValue( bool isAddingValue )
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiFieldHandle::setValueFromUiEditor( const QVariant& uiValue )
void PdmUiFieldHandle::setValueFromUiEditor( const QVariant& uiValue, bool notifyFieldChanged )
{
}

View File

@ -30,7 +30,7 @@ public:
private:
friend class PdmUiCommandSystemProxy;
friend class CmdFieldChangeExec;
virtual void setValueFromUiEditor( const QVariant& uiValue );
virtual void setValueFromUiEditor( const QVariant& uiValue, bool notifyFieldChanged );
// This is needed to handle custom types in QVariants since operator == between QVariant does not work when they use
// custom types.
virtual bool isQVariantDataEqual( const QVariant& oldUiBasedQVariant, const QVariant& newUiBasedQVariant ) const;