From 6ff75e3700e26d316de9bca978889523c0395558 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 18 Mar 2026 11:00:53 +0100 Subject: [PATCH] SummaryMultiPlot: Improve sub-plot stepping and duplicate plot handling --- .../Summary/RiaSummaryPlotTemplateTools.cpp | 2 + .../Summary/RimSummaryMultiPlot.cpp | 188 ++++++++++++------ .../Summary/RimSummaryMultiPlot.h | 10 +- .../Summary/RimSummaryMultiPlotCollection.cpp | 28 +-- .../Summary/RimSummaryMultiPlotCollection.h | 11 +- .../UserInterface/RiuPlotMainWindow.cpp | 2 +- 6 files changed, 136 insertions(+), 105 deletions(-) diff --git a/ApplicationLibCode/Application/Tools/Summary/RiaSummaryPlotTemplateTools.cpp b/ApplicationLibCode/Application/Tools/Summary/RiaSummaryPlotTemplateTools.cpp index ef33671f70..20e9806a53 100644 --- a/ApplicationLibCode/Application/Tools/Summary/RiaSummaryPlotTemplateTools.cpp +++ b/ApplicationLibCode/Application/Tools/Summary/RiaSummaryPlotTemplateTools.cpp @@ -217,6 +217,8 @@ RimSummaryMultiPlot* RicSummaryPlotTemplateTools::create( const QString& newSummaryPlot->loadDataAndUpdate(); collections->updateConnectedEditors(); + newSummaryPlot->updatePlots(); + return newSummaryPlot; } diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryMultiPlot.cpp b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryMultiPlot.cpp index ef9c031f4e..34af9548e6 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryMultiPlot.cpp +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryMultiPlot.cpp @@ -112,7 +112,6 @@ void RimSummaryMultiPlot::clearLayoutInfo() /// //-------------------------------------------------------------------------------------------------- RimSummaryMultiPlot::RimSummaryMultiPlot() - : duplicatePlot( this ) { CAF_PDM_InitObject( "Multi Summary Plot", ":/SummaryPlotLight16x16.png" ); setDeletable( true ); @@ -492,7 +491,10 @@ void RimSummaryMultiPlot::fieldChangedByUi( const caf::PdmFieldHandle* changedFi else if ( changedField == &m_createPlotDuplicate ) { m_createPlotDuplicate = false; - duplicate(); + if ( auto plotCollection = RimMainPlotCollection::current()->summaryMultiPlotCollection() ) + { + plotCollection->duplicatePlot( this ); + } } else if ( changedField == &m_appendNextPlot ) { @@ -689,6 +691,8 @@ std::vector RimSummaryMultiPlot::fieldsToShowInToolbar() auto& sourceObject = m_sourceStepping(); if ( sourceObject ) { + sourceObject->setSourceSteppingObject( steppingSourceObject() ); + auto fields = sourceObject->fieldsToShowInToolbar(); toolBarFields.insert( std::end( toolBarFields ), std::begin( fields ), std::end( fields ) ); } @@ -1302,14 +1306,6 @@ void RimSummaryMultiPlot::summaryPlotItemInfos( QList* o } } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimSummaryMultiPlot::duplicate() -{ - duplicatePlot.send( this ); -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -1611,91 +1607,151 @@ void RimSummaryMultiPlot::onPlotAdditionOrRemoval() RimMultiPlot::onPlotAdditionOrRemoval(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimSummaryMultiPlot::isStepDimensionSharedAmongSubPlots() +{ + using Dim = RimSummaryDataSourceStepping::SourceSteppingDimension; + + populateNameHelper( m_nameHelper.get() ); + + switch ( m_sourceStepping->stepDimension() ) + { + case Dim::SUMMARY_CASE: + case Dim::ENSEMBLE: + return m_nameHelper->isCaseInTitle(); + case Dim::WELL: + return m_nameHelper->isWellNameInTitle(); + case Dim::GROUP: + return m_nameHelper->isGroupNameInTitle(); + case Dim::NETWORK: + return m_nameHelper->isNetworkInTitle(); + case Dim::REGION: + return m_nameHelper->isRegionInTitle(); + case Dim::VECTOR: + return !m_nameHelper->titleVectorName().empty(); + case Dim::BLOCK: + return m_nameHelper->isBlockInTitle(); + case Dim::WELL_SEGMENT: + return m_nameHelper->isSegmentInTitle(); + case Dim::WELL_CONNECTION: + return m_nameHelper->isConnectionInTitle(); + case Dim::WELL_COMPLETION_NUMBER: + return m_nameHelper->isWellCompletionInTitle(); + default: + break; + } + + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmObject* RimSummaryMultiPlot::steppingSourceObject() +{ + if ( !isStepDimensionSharedAmongSubPlots() ) + { + auto* selectedPlot = caf::SelectionManager::instance()->selectedItemOfType(); + if ( selectedPlot && selectedPlot->firstAncestorOrThisOfType() == this ) return selectedPlot; + } + return this; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimSummaryMultiPlot::appendSubPlotByStepping( int direction ) { - std::vector plotsForStepping; + m_sourceStepping->setSourceSteppingObject( steppingSourceObject() ); - bool isMultiPlotSelected = ( caf::SelectionManager::instance()->selectedItemOfType() != nullptr ); - if ( isMultiPlotSelected ) + auto applySteppingToPlots = []( const std::vector& summaryPlots, RimSummaryPlotSourceStepping* sourceStepper, int direction ) { - duplicate(); + if ( !sourceStepper ) return; - // The duplicate operation selects duplicated plot by default. Select this as current item to continue stepping on this plot - RiuPlotMainWindowTools::selectAsCurrentItem( this ); + for ( auto newPlot : summaryPlots ) + { + if ( sourceStepper->stepDimension() == RimSummaryDataSourceStepping::SourceSteppingDimension::SUMMARY_CASE ) + { + RimSummaryCase* newCase = sourceStepper->stepCase( direction ); + for ( auto curve : newPlot->allCurves() ) + { + curve->setSummaryCaseY( newCase ); - plotsForStepping = summaryPlots(); + // NOTE: If summary cross plots should be handled here, we also need to call + // curve->setSummaryCaseX( newCase ); + // Setting summaryCaseX with a default uninitialized summary address causes issues for the summary + // name analyzer + } + } + else if ( sourceStepper->stepDimension() == RimSummaryDataSourceStepping::SourceSteppingDimension::ENSEMBLE ) + { + RimSummaryEnsemble* newEnsemble = sourceStepper->stepEnsemble( direction ); + for ( auto curveSet : newPlot->curveSets() ) + { + curveSet->setSummaryEnsemble( newEnsemble ); + } + } + else + { + std::vector newCurveAdrs; + + auto curveAddressProviders = RiaSummaryAddressModifier::createAddressProviders( newPlot ); + for ( const auto& adr : RiaSummaryAddressModifier::curveAddresses( curveAddressProviders ) ) + { + const auto adrX = sourceStepper->stepAddress( adr.summaryAddressX(), direction ); + const auto adrY = sourceStepper->stepAddress( adr.summaryAddressY(), direction ); + newCurveAdrs.push_back( RiaSummaryCurveAddress( adrX, adrY ) ); + } + + RiaSummaryAddressModifier::applyAddressesToCurveAddressProviders( curveAddressProviders, newCurveAdrs ); + } + } + }; + + if ( m_sourceStepping()->isAtEnd( direction ) ) return; + + if ( caf::SelectionManager::instance()->selectedItemOfType() != nullptr ) + { + if ( auto plotCollection = RimMainPlotCollection::current()->summaryMultiPlotCollection() ) + { + auto copy = plotCollection->duplicatePlot( this ); + + applySteppingToPlots( copy->summaryPlots(), m_sourceStepping(), direction ); + + copy->loadDataAndUpdate(); + copy->updateConnectedEditors(); + copy->updateSourceStepper(); + } } else { std::vector plots = m_sourceStepping->plotsMatchingStepSettings( summaryPlots() ); if ( !plots.empty() ) { - auto newPlots = RiaSummaryPlotTools::duplicatePlots( plots ); + std::vector summaryPlots; + auto newPlots = RiaSummaryPlotTools::duplicatePlots( plots ); for ( auto plot : newPlots ) { if ( RimSummaryPlot* newPlot = dynamic_cast( plot ) ) { addPlot( newPlot ); newPlot->resolveReferencesRecursively(); - - plotsForStepping.push_back( newPlot ); + summaryPlots.push_back( newPlot ); } } + applySteppingToPlots( summaryPlots, m_sourceStepping(), direction ); } - } - for ( auto newPlot : plotsForStepping ) - { - if ( m_sourceStepping()->stepDimension() == RimSummaryDataSourceStepping::SourceSteppingDimension::SUMMARY_CASE ) - { - RimSummaryCase* newCase = m_sourceStepping()->stepCase( direction ); - for ( auto curve : newPlot->allCurves() ) - { - curve->setSummaryCaseY( newCase ); + loadDataAndUpdate(); + updateConnectedEditors(); - // NOTE: If summary cross plots should be handled here, we also need to call - // curve->setSummaryCaseX( newCase ); - // Setting summaryCaseX with a default uninitialized summary address causes issues for the summary - // name analyzer - } - } - else if ( m_sourceStepping()->stepDimension() == RimSummaryDataSourceStepping::SourceSteppingDimension::ENSEMBLE ) - { - RimSummaryEnsemble* newEnsemble = m_sourceStepping()->stepEnsemble( direction ); - for ( auto curveSet : newPlot->curveSets() ) - { - curveSet->setSummaryEnsemble( newEnsemble ); - } - } - else - { - std::vector newCurveAdrs; - - auto curveAddressProviders = RiaSummaryAddressModifier::createAddressProviders( newPlot ); - for ( const auto& adr : RiaSummaryAddressModifier::curveAddresses( curveAddressProviders ) ) - { - const auto adrX = m_sourceStepping()->stepAddress( adr.summaryAddressX(), direction ); - const auto adrY = m_sourceStepping()->stepAddress( adr.summaryAddressY(), direction ); - newCurveAdrs.push_back( RiaSummaryCurveAddress( adrX, adrY ) ); - } - - RiaSummaryAddressModifier::applyAddressesToCurveAddressProviders( curveAddressProviders, newCurveAdrs ); - } - } - - loadDataAndUpdate(); - updateConnectedEditors(); - - if ( !isMultiPlotSelected && !summaryPlots().empty() ) - { - // Select the last plot in the list as the current item to be able to append plots for the next object type (well, region, etc.) RiuPlotMainWindowTools::selectAsCurrentItem( summaryPlots().back() ); + + updateSourceStepper(); } - updateSourceStepper(); RiuPlotMainWindowTools::refreshToolbars(); } diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryMultiPlot.h b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryMultiPlot.h index 6b7ed3e7b9..53dafd5d29 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryMultiPlot.h +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryMultiPlot.h @@ -24,8 +24,6 @@ #include "cafPdmChildField.h" #include "cafPdmObject.h" #include "cafPdmUiItem.h" -#include "cafSignal.h" - #include #include @@ -45,9 +43,6 @@ class RimSummaryMultiPlot : public RimMultiPlot, public RimSummaryDataSourceStep { CAF_PDM_HEADER_INIT; -public: - caf::Signal duplicatePlot; - public: enum class AxisRangeAggregation { @@ -144,11 +139,12 @@ private: void setAutoValueStates(); static void setAutoValueStatesForPlot( RimSummaryPlot* summaryPlot, bool isMinMaxOverridden, bool isAppearanceOverridden ); - void duplicate(); - void appendSubPlotByStepping( int direction ); void appendCurveByStepping( int direction ); + bool isStepDimensionSharedAmongSubPlots(); + caf::PdmObject* steppingSourceObject(); + void onSubPlotChanged( const caf::SignalEmitter* emitter ); void onSubPlotAxisChanged( const caf::SignalEmitter* emitter, RimSummaryPlot* summaryPlot ); void onSubPlotAxisReloadRequired( const caf::SignalEmitter* emitter, RimSummaryPlot* summaryPlot ); diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryMultiPlotCollection.cpp b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryMultiPlotCollection.cpp index dae842c3fa..3661a91c94 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryMultiPlotCollection.cpp +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryMultiPlotCollection.cpp @@ -61,10 +61,6 @@ RimSummaryMultiPlotCollection::~RimSummaryMultiPlotCollection() //-------------------------------------------------------------------------------------------------- void RimSummaryMultiPlotCollection::initAfterRead() { - for ( auto& plot : m_summaryMultiPlots ) - { - plot->duplicatePlot.connect( this, &RimSummaryMultiPlotCollection::onDuplicatePlot ); - } } //-------------------------------------------------------------------------------------------------- @@ -89,7 +85,6 @@ std::vector RimSummaryMultiPlotCollection::multiPlots() co void RimSummaryMultiPlotCollection::addSummaryMultiPlot( RimSummaryMultiPlot* plot ) { m_summaryMultiPlots().push_back( plot ); - plot->duplicatePlot.connect( this, &RimSummaryMultiPlotCollection::onDuplicatePlot ); } //-------------------------------------------------------------------------------------------------- @@ -118,23 +113,6 @@ size_t RimSummaryMultiPlotCollection::plotCount() const return m_summaryMultiPlots.size(); } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimSummaryMultiPlotCollection::onDuplicatePlot( const caf::SignalEmitter* emitter, RimSummaryMultiPlot* plotToDuplicate ) -{ - duplicatePlot( plotToDuplicate ); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimSummaryMultiPlotCollection::onRefreshTree( const caf::SignalEmitter* emitter, RimSummaryMultiPlot* plotRequesting ) -{ - if ( !plotRequesting ) return; - updateConnectedEditors(); -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -224,9 +202,9 @@ void RimSummaryMultiPlotCollection::summaryPlotItemInfos( QListcopyObject(); addSummaryMultiPlot( plotCopy ); @@ -239,6 +217,8 @@ void RimSummaryMultiPlotCollection::duplicatePlot( RimSummaryMultiPlot* plotToDu updateConnectedEditors(); RiuPlotMainWindowTools::selectAsCurrentItem( plotCopy ); + + return plotCopy; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryMultiPlotCollection.h b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryMultiPlotCollection.h index 6db0fe2d42..c19d392346 100644 --- a/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryMultiPlotCollection.h +++ b/ApplicationLibCode/ProjectDataModel/Summary/RimSummaryMultiPlotCollection.h @@ -44,10 +44,10 @@ public: std::vector multiPlots() const; - void addSummaryMultiPlot( RimSummaryMultiPlot* plot ); - void summaryPlotItemInfos( QList* optionInfos ) const; - void duplicatePlot( RimSummaryMultiPlot* plotToDuplicate ); - void removePlotNoUpdate( RimSummaryMultiPlot* plotToRemove ); + void addSummaryMultiPlot( RimSummaryMultiPlot* plot ); + void summaryPlotItemInfos( QList* optionInfos ) const; + RimSummaryMultiPlot* duplicatePlot( RimSummaryMultiPlot* plotToDuplicate ); + void removePlotNoUpdate( RimSummaryMultiPlot* plotToRemove ); void updateSummaryNameHasChanged(); @@ -59,9 +59,6 @@ private: void onChildrenUpdated( caf::PdmChildArrayFieldHandle* childArray, std::vector& updatedObjects ) override; void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override; - void onDuplicatePlot( const caf::SignalEmitter* emitter, RimSummaryMultiPlot* plotToDuplicate ); - void onRefreshTree( const caf::SignalEmitter* emitter, RimSummaryMultiPlot* plotRequesting ); - void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override; void childFieldChangedByUi( const caf::PdmFieldHandle* changedChildField ) override; diff --git a/ApplicationLibCode/UserInterface/RiuPlotMainWindow.cpp b/ApplicationLibCode/UserInterface/RiuPlotMainWindow.cpp index 2a5784aa5d..93a181afbf 100644 --- a/ApplicationLibCode/UserInterface/RiuPlotMainWindow.cpp +++ b/ApplicationLibCode/UserInterface/RiuPlotMainWindow.cpp @@ -758,8 +758,8 @@ void RiuPlotMainWindow::updateMultiPlotToolBar() if ( !m_multiPlotToolBarEditor->isEditorDataEqualAndValid( toolBarFields ) ) { m_multiPlotToolBarEditor->setFields( toolBarFields ); - m_multiPlotToolBarEditor->updateUi(); } + m_multiPlotToolBarEditor->updateUi(); m_multiPlotToolBarEditor->show(); }