#13901 ShowPlotData: Invert dependencies via capability mixins and text-dialog signal

This commit is contained in:
Magne Sjaastad
2026-04-20 14:09:25 +02:00
parent 99910c3d7d
commit bd3836ba25
26 changed files with 612 additions and 298 deletions
@@ -20,33 +20,19 @@
#include "RiaFeatureCommandContext.h"
#include "RiaGuiApplication.h"
#include "RiaPreferencesSummary.h"
#include "RiaQDateTimeTools.h"
#include "RimAnalysisPlot.h"
#include "RimCorrelationMatrixPlot.h"
#include "RimCorrelationPlot.h"
#include "RimCorrelationReportPlot.h"
#include "RimGridCrossPlot.h"
#include "RimGridCrossPlotCurve.h"
#include "RimParameterResultCrossPlot.h"
#include "RimParameterRftCrossPlot.h"
#include "SummaryPlotCommands/RicAsciiExportSummaryPlotFeature.h"
#include "RimPlainPlotDataProducer.h"
#include "RimPlot.h"
#include "RimPlotWindow.h"
#include "RimProject.h"
#include "RimRftCorrelationReportPlot.h"
#include "RimRftTornadoPlot.h"
#include "RimSummaryPlot.h"
#include "RimWellAllocationOverTimePlot.h"
#include "RimWellLogPlot.h"
#include "RimWellLogTrack.h"
#include "VerticalFlowPerformance/RimCustomVfpPlot.h"
#include "RimReportPlotGroup.h"
#include "RimTabbedTextProducer.h"
#include "RimTabbedTextProvider.h"
#include "RiuPlotMainWindow.h"
#include "RiuTextDialog.h"
#include "cafPdmPointer.h"
#include "cafProgressInfo.h"
#include "cafSelectionManagerTools.h"
#include <QAction>
@@ -54,124 +40,6 @@
CAF_CMD_SOURCE_INIT( RicShowPlotDataFeature, "RicShowPlotDataFeature" );
//--------------------------------------------------------------------------------------------------
/// Private text provider class for summary plots
//--------------------------------------------------------------------------------------------------
class RiuTabbedSummaryPlotTextProvider : public RiuTabbedTextProvider
{
public:
RiuTabbedSummaryPlotTextProvider( RimSummaryPlot* summaryPlot )
: m_summaryPlot( summaryPlot )
{
}
bool isValid() const override { return m_summaryPlot.notNull(); }
QString description() const override
{
CVF_ASSERT( m_summaryPlot.notNull() && "Need to check that provider is valid" );
return m_summaryPlot->description();
}
QString tabTitle( int tabIndex ) const override
{
auto allTabs = tabs();
CVF_ASSERT( tabIndex < (int)allTabs.size() );
RiaDefines::DateTimePeriod timePeriod = allTabs[tabIndex];
if ( timePeriod == RiaDefines::DateTimePeriod::NONE )
{
return "No Resampling";
}
return QString( "%1" ).arg( RiaQDateTimeTools::dateTimePeriodName( timePeriod ) );
}
QString tabText( int tabIndex ) const override
{
CVF_ASSERT( m_summaryPlot.notNull() && "Need to check that provider is valid" );
RiaDefines::DateTimePeriod timePeriod = indexToPeriod( tabIndex );
RiaPreferencesSummary* prefs = RiaPreferencesSummary::current();
return m_summaryPlot->asciiDataForSummaryPlotExport( timePeriod, prefs->showSummaryTimeAsLongString() );
}
int tabCount() const override { return (int)tabs().size(); }
private:
static RiaDefines::DateTimePeriod indexToPeriod( int tabIndex )
{
auto allTabs = tabs();
CVF_ASSERT( tabIndex < (int)allTabs.size() );
RiaDefines::DateTimePeriod timePeriod = allTabs[tabIndex];
return timePeriod;
}
static std::vector<RiaDefines::DateTimePeriod> tabs()
{
std::vector<RiaDefines::DateTimePeriod> dateTimePeriods;
dateTimePeriods.emplace_back( RiaDefines::DateTimePeriod::NONE );
dateTimePeriods.emplace_back( RiaDefines::DateTimePeriod::YEAR );
dateTimePeriods.emplace_back( RiaDefines::DateTimePeriod::HALFYEAR );
dateTimePeriods.emplace_back( RiaDefines::DateTimePeriod::QUARTER );
dateTimePeriods.emplace_back( RiaDefines::DateTimePeriod::MONTH );
dateTimePeriods.emplace_back( RiaDefines::DateTimePeriod::WEEK );
dateTimePeriods.emplace_back( RiaDefines::DateTimePeriod::DAY );
dateTimePeriods.emplace_back( RiaDefines::DateTimePeriod::HOUR );
dateTimePeriods.emplace_back( RiaDefines::DateTimePeriod::MINUTE );
return dateTimePeriods;
}
private:
caf::PdmPointer<RimSummaryPlot> m_summaryPlot;
};
//--------------------------------------------------------------------------------------------------
/// Private text provider class for grid cross plots
//--------------------------------------------------------------------------------------------------
class RiuTabbedGridCrossPlotTextProvider : public RiuTabbedTextProvider
{
public:
RiuTabbedGridCrossPlotTextProvider( RimGridCrossPlot* crossPlot )
: m_crossPlot( crossPlot )
{
}
bool isValid() const override { return m_crossPlot.notNull(); }
QString description() const override
{
CVF_ASSERT( m_crossPlot.notNull() && "Need to check that provider is valid" );
return m_crossPlot->createAutoName();
}
QString tabTitle( int tabIndex ) const override
{
CVF_ASSERT( m_crossPlot.notNull() && "Need to check that provider is valid" );
return m_crossPlot->asciiTitleForPlotExport( tabIndex );
}
QString tabText( int tabIndex ) const override
{
CVF_ASSERT( m_crossPlot.notNull() && "Need to check that provider is valid" );
return m_crossPlot->asciiDataForGridCrossPlotExport( tabIndex );
}
int tabCount() const override
{
CVF_ASSERT( m_crossPlot.notNull() && "Need to check that provider is valid" );
return (int)m_crossPlot->dataSets().size();
}
private:
caf::PdmPointer<RimGridCrossPlot> m_crossPlot;
};
//--------------------------------------------------------------------------------------------------
///
///
/// RicShowPlotDataFeature
///
///
//--------------------------------------------------------------------------------------------------
bool RicShowPlotDataFeature::isCommandEnabled() const
@@ -185,20 +53,13 @@ bool RicShowPlotDataFeature::isCommandEnabled() const
std::vector<RimPlotWindow*> selection;
getSelection( selection );
int validPlots = 0;
for ( auto plot : selection )
{
if ( dynamic_cast<RimSummaryPlot*>( plot ) || dynamic_cast<RimWellLogPlot*>( plot ) || dynamic_cast<RimWellLogTrack*>( plot ) ||
dynamic_cast<RimGridCrossPlot*>( plot ) || dynamic_cast<RimCustomVfpPlot*>( plot ) ||
dynamic_cast<RimWellAllocationOverTimePlot*>( plot ) || dynamic_cast<RimAnalysisPlot*>( plot ) ||
dynamic_cast<RimCorrelationMatrixPlot*>( plot ) || dynamic_cast<RimAbstractCorrelationPlot*>( plot ) ||
dynamic_cast<RimCorrelationReportPlot*>( plot ) || dynamic_cast<RimRftCorrelationReportPlot*>( plot ) )
{
validPlots++;
}
if ( dynamic_cast<const RimTabbedTextProducer*>( plot ) ) return true;
if ( dynamic_cast<const RimReportPlotGroup*>( plot ) ) return true;
if ( dynamic_cast<const RimPlainPlotDataProducer*>( plot ) ) return true;
}
return ( validPlots > 0 );
return false;
}
//--------------------------------------------------------------------------------------------------
@@ -216,7 +77,6 @@ void RicShowPlotDataFeature::onActionTriggered( bool isChecked )
}
RicShowPlotDataFeature::showTextWindow( title, content );
return;
}
@@ -225,93 +85,34 @@ void RicShowPlotDataFeature::onActionTriggered( bool isChecked )
std::vector<RimPlotWindow*> selection;
getSelection( selection );
// Using RiuTabbedSummaryPlotTextProvider
std::vector<RimSummaryPlot*> summaryPlots;
// Using RiuTabbedGridCrossPlotTextProvider
std::vector<RimGridCrossPlot*> crossPlots;
// Special handling for well log plots
std::vector<RimWellLogPlot*> wellLogPlots;
// Show content using RimPlot::description() and RimPlot::asciiDataForPlotExport()
std::vector<RimPlot*> rimPlots;
for ( auto plot : selection )
auto showPlainForProducer = []( RimPlainPlotDataProducer* producer )
{
if ( auto sumPlot = dynamic_cast<RimSummaryPlot*>( plot ) )
{
summaryPlots.push_back( sumPlot );
continue;
}
if ( auto xPlot = dynamic_cast<RimGridCrossPlot*>( plot ) )
{
crossPlots.push_back( xPlot );
continue;
}
if ( auto wellLogPlot = dynamic_cast<RimWellLogPlot*>( plot ) )
{
wellLogPlots.push_back( wellLogPlot );
continue;
}
if ( auto correlationReportPlot = dynamic_cast<RimCorrelationReportPlot*>( plot ) )
{
// A correlation report plot contains three plots. Add them as individual plots to rimPlots to make the data available in three
// individual text dialogs.
rimPlots.push_back( correlationReportPlot->matrixPlot() );
rimPlots.push_back( correlationReportPlot->correlationPlot() );
rimPlots.push_back( correlationReportPlot->crossPlot() );
continue;
}
if ( auto rftReportPlot = dynamic_cast<RimRftCorrelationReportPlot*>( plot ) )
{
rimPlots.push_back( rftReportPlot->crossPlot() );
rimPlots.push_back( rftReportPlot->correlationPlot() );
continue;
}
if ( auto rimPlot = dynamic_cast<RimPlot*>( plot ) )
{
rimPlots.push_back( rimPlot );
}
}
for ( RimSummaryPlot* summaryPlot : summaryPlots )
{
auto textProvider = new RiuTabbedSummaryPlotTextProvider( summaryPlot );
RicShowPlotDataFeature::showTabbedTextWindow( textProvider );
}
for ( RimGridCrossPlot* crossPlot : crossPlots )
{
auto textProvider = new RiuTabbedGridCrossPlotTextProvider( crossPlot );
RicShowPlotDataFeature::showTabbedTextWindow( textProvider );
}
for ( auto rimPlot : rimPlots )
{
QString title = rimPlot->description();
QString text = title;
text += "\n";
text += "\n";
text += rimPlot->asciiDataForPlotExport();
QString title = producer->description();
QString text = title + "\n\n" + producer->asciiDataForPlotExport();
RicShowPlotDataFeature::showTextWindow( title, text );
}
};
for ( auto wellLogPlot : wellLogPlots )
for ( auto* plot : selection )
{
QString title = wellLogPlot->description();
QString text = title;
text += "\n";
text += "\n";
text += wellLogPlot->asciiDataForPlotExport();
if ( auto* producer = dynamic_cast<RimTabbedTextProducer*>( plot ) )
{
RicShowPlotDataFeature::showTabbedTextWindow( producer->createTabbedTextProvider() );
continue;
}
RicShowPlotDataFeature::showTextWindow( title, text );
if ( auto* group = dynamic_cast<RimReportPlotGroup*>( plot ) )
{
for ( auto* child : group->childPlotsForTextExport() )
{
if ( child ) showPlainForProducer( child );
}
continue;
}
if ( auto* plainProducer = dynamic_cast<RimPlainPlotDataProducer*>( plot ) )
{
showPlainForProducer( plainProducer );
}
}
}
@@ -327,13 +128,24 @@ void RicShowPlotDataFeature::setupActionLook( QAction* actionToSetup )
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicShowPlotDataFeature::showTabbedTextWindow( RiuTabbedTextProvider* textProvider )
void RicShowPlotDataFeature::showTabbedTextWindow( std::unique_ptr<RimTabbedTextProvider> textProvider )
{
RiuPlotMainWindow* plotwindow = RiaGuiApplication::instance()->mainPlotWindow();
CVF_ASSERT( plotwindow );
auto* textWidget = new RiuTabbedTextDialog( textProvider );
auto* textWidget = new RiuTabbedTextDialog( std::move( textProvider ) );
textWidget->setMinimumSize( 800, 600 );
QObject::connect( textWidget,
&RiuTabbedTextDialog::exportToFileRequested,
[]( const QString& title, const QString& text )
{
QString defaultDir = RicAsciiExportSummaryPlotFeature::defaultExportDir();
QString fileName = RicAsciiExportSummaryPlotFeature::getFileNameFromUserDialog( title, defaultDir );
if ( fileName.isEmpty() ) return;
RicAsciiExportSummaryPlotFeature::exportTextToFile( fileName, text );
} );
plotwindow->addToTemporaryWidgets( textWidget );
textWidget->show();
textWidget->redrawText();
@@ -20,10 +20,11 @@
#include "cafCmdFeature.h"
#include <memory>
#include <vector>
class RiuTabbedTextProvider;
class RimPlotWindow;
class RimTabbedTextProvider;
//==================================================================================================
///
@@ -41,6 +42,6 @@ private:
void getSelection( std::vector<RimPlotWindow*>& selection ) const;
public:
static void showTabbedTextWindow( RiuTabbedTextProvider* textProvider );
static void showTabbedTextWindow( std::unique_ptr<RimTabbedTextProvider> textProvider );
static void showTextWindow( const QString& title, const QString& text );
};
@@ -49,6 +49,10 @@ set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RimPltPlotCollection.h
${CMAKE_CURRENT_LIST_DIR}/RimPlot.h
${CMAKE_CURRENT_LIST_DIR}/RimPlotWindow.h
${CMAKE_CURRENT_LIST_DIR}/RimPlainPlotDataProducer.h
${CMAKE_CURRENT_LIST_DIR}/RimReportPlotGroup.h
${CMAKE_CURRENT_LIST_DIR}/RimTabbedTextProducer.h
${CMAKE_CURRENT_LIST_DIR}/RimTabbedTextProvider.h
${CMAKE_CURRENT_LIST_DIR}/RimMultiPlot.h
${CMAKE_CURRENT_LIST_DIR}/RimDepthTrackPlot.h
${CMAKE_CURRENT_LIST_DIR}/RimWellBoreStabilityPlot.h
@@ -313,6 +313,14 @@ RimParameterResultCrossPlot* RimCorrelationReportPlot::crossPlot() const
return m_parameterResultCrossPlot();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimPlot*> RimCorrelationReportPlot::childPlotsForTextExport() const
{
return { matrixPlot(), correlationPlot(), crossPlot() };
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -18,6 +18,7 @@
#pragma once
#include "RimPlotWindow.h"
#include "RimReportPlotGroup.h"
#include "cafPdmChildField.h"
#include "cafPdmField.h"
@@ -39,7 +40,7 @@ class CDockManager;
class CDockWidget;
} // namespace ads
class RimCorrelationReportPlot : public QObject, public RimPlotWindow
class RimCorrelationReportPlot : public QObject, public RimPlotWindow, public RimReportPlotGroup
{
CAF_PDM_HEADER_INIT;
@@ -57,6 +58,8 @@ public:
RimCorrelationPlot* correlationPlot() const;
RimParameterResultCrossPlot* crossPlot() const;
std::vector<RimPlot*> childPlotsForTextExport() const override;
int subTitleFontSize() const;
int axisTitleFontSize() const;
int axisValueFontSize() const;
@@ -460,6 +460,14 @@ RimRftTornadoPlot* RimRftCorrelationReportPlot::correlationPlot() const
return m_correlationPlot();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimPlot*> RimRftCorrelationReportPlot::childPlotsForTextExport() const
{
return { crossPlot(), correlationPlot() };
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -18,6 +18,7 @@
#pragma once
#include "RimPlotWindow.h"
#include "RimReportPlotGroup.h"
#include "cafPdmChildField.h"
#include "cafPdmField.h"
@@ -41,7 +42,7 @@ class CDockWidget;
/// RimParameterRftCrossPlot (ensemble parameter vs mean pressure in a depth range).
///
//==================================================================================================
class RimRftCorrelationReportPlot : public QObject, public RimPlotWindow
class RimRftCorrelationReportPlot : public QObject, public RimPlotWindow, public RimReportPlotGroup
{
CAF_PDM_HEADER_INIT;
@@ -59,6 +60,8 @@ public:
RimParameterRftCrossPlot* crossPlot() const;
RimRftTornadoPlot* correlationPlot() const;
std::vector<RimPlot*> childPlotsForTextExport() const override;
void initializeFromSourcePlot( RimWellRftPlot* source );
private:
@@ -4,6 +4,7 @@ set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlotCurve.h
${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlotRegressionCurve.h
${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlotDataSet.h
${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlotTextProvider.h
${CMAKE_CURRENT_LIST_DIR}/RimSaturationPressurePlot.h
${CMAKE_CURRENT_LIST_DIR}/RimSaturationPressurePlotCollection.h
)
@@ -14,6 +15,7 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlotCurve.cpp
${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlotRegressionCurve.cpp
${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlotDataSet.cpp
${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlotTextProvider.cpp
${CMAKE_CURRENT_LIST_DIR}/RimSaturationPressurePlot.cpp
${CMAKE_CURRENT_LIST_DIR}/RimSaturationPressurePlotCollection.cpp
)
@@ -26,6 +26,7 @@
#include "RimGridCrossPlotCurve.h"
#include "RimGridCrossPlotDataSet.h"
#include "RimGridCrossPlotTextProvider.h"
#include "RimMultiPlot.h"
#include "RimPlotAxisProperties.h"
@@ -641,6 +642,14 @@ QString RimGridCrossPlot::asciiDataForPlotExport() const
return fullData;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::unique_ptr<RimTabbedTextProvider> RimGridCrossPlot::createTabbedTextProvider() const
{
return std::make_unique<RimGridCrossPlotTextProvider>( const_cast<RimGridCrossPlot*>( this ) );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -23,6 +23,7 @@
#include "RimNameConfig.h"
#include "RimPlot.h"
#include "RimTabbedTextProducer.h"
#include <QPointer>
@@ -53,7 +54,7 @@ private:
void doEnableAllAutoNameTags( bool enable ) override;
};
class RimGridCrossPlot : public RimPlot, public RimNameConfigHolderInterface
class RimGridCrossPlot : public RimPlot, public RimNameConfigHolderInterface, public RimTabbedTextProducer
{
Q_OBJECT;
CAF_PDM_HEADER_INIT;
@@ -92,6 +93,8 @@ public:
QString asciiTitleForPlotExport( int dataSetIndex ) const;
QString asciiDataForGridCrossPlotExport( int dataSetIndex ) const;
std::unique_ptr<RimTabbedTextProvider> createTabbedTextProvider() const override;
bool isXAxisLogarithmic() const;
bool isYAxisLogarithmic() const;
void setYAxisInverted( bool inverted );
@@ -0,0 +1,75 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2026 Equinor ASA
//
// ResInsight 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.
//
// ResInsight 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.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RimGridCrossPlotTextProvider.h"
#include "RimGridCrossPlot.h"
#include "cafAssert.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimGridCrossPlotTextProvider::RimGridCrossPlotTextProvider( RimGridCrossPlot* crossPlot )
: m_crossPlot( crossPlot )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimGridCrossPlotTextProvider::isValid() const
{
return m_crossPlot.notNull();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimGridCrossPlotTextProvider::description() const
{
CAF_ASSERT( m_crossPlot.notNull() && "Need to check that provider is valid" );
return m_crossPlot->createAutoName();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimGridCrossPlotTextProvider::tabTitle( int tabIndex ) const
{
CAF_ASSERT( m_crossPlot.notNull() && "Need to check that provider is valid" );
return m_crossPlot->asciiTitleForPlotExport( tabIndex );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimGridCrossPlotTextProvider::tabText( int tabIndex ) const
{
CAF_ASSERT( m_crossPlot.notNull() && "Need to check that provider is valid" );
return m_crossPlot->asciiDataForGridCrossPlotExport( tabIndex );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int RimGridCrossPlotTextProvider::tabCount() const
{
CAF_ASSERT( m_crossPlot.notNull() && "Need to check that provider is valid" );
return static_cast<int>( m_crossPlot->dataSets().size() );
}
@@ -0,0 +1,43 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2026 Equinor ASA
//
// ResInsight 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.
//
// ResInsight 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.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RimTabbedTextProvider.h"
#include "cafPdmPointer.h"
class RimGridCrossPlot;
//==================================================================================================
/// Tabbed text provider for a RimGridCrossPlot. Each tab corresponds to a data set in the plot.
//==================================================================================================
class RimGridCrossPlotTextProvider : public RimTabbedTextProvider
{
public:
explicit RimGridCrossPlotTextProvider( RimGridCrossPlot* crossPlot );
bool isValid() const override;
QString description() const override;
QString tabTitle( int tabIndex ) const override;
QString tabText( int tabIndex ) const override;
int tabCount() const override;
private:
caf::PdmPointer<RimGridCrossPlot> m_crossPlot;
};
@@ -24,6 +24,7 @@
#include "RimAbstractPlotCollection.h"
#include "RimEnsembleWellLogStatistics.h"
#include "RimPlainPlotDataProducer.h"
#include "RimPlot.h"
#include "RimPlotWindow.h"
@@ -56,7 +57,10 @@ class QKeyEvent;
///
///
//==================================================================================================
class RimDepthTrackPlot : public RimTypedPlotCollection<RimPlot>, public RimPlotWindow, public RimNameConfigHolderInterface
class RimDepthTrackPlot : public RimTypedPlotCollection<RimPlot>,
public RimPlotWindow,
public RimNameConfigHolderInterface,
public RimPlainPlotDataProducer
{
CAF_PDM_HEADER_INIT;
@@ -155,7 +159,7 @@ public:
void setAvailableDepthUnits( const std::set<RiaDefines::DepthUnitType>& depthUnits );
void setAvailableDepthTypes( const std::set<DepthTypeEnum>& depthTypes );
QString asciiDataForPlotExport() const;
QString asciiDataForPlotExport() const override;
void handleKeyPressEvent( QKeyEvent* keyEvent );
void onChildDeleted( caf::PdmChildArrayFieldHandle* childArray, std::vector<caf::PdmObjectHandle*>& referringObjects ) override;
@@ -0,0 +1,34 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2026 Equinor ASA
//
// ResInsight 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.
//
// ResInsight 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.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include <QString>
//==================================================================================================
/// Capability mixin: a plot or plot window that can produce a plain-text
/// representation for the "Show Plot Data" feature.
//==================================================================================================
class RimPlainPlotDataProducer
{
public:
virtual ~RimPlainPlotDataProducer() = default;
virtual QString description() const = 0;
virtual QString asciiDataForPlotExport() const = 0;
};
@@ -20,6 +20,7 @@
#include "RiaDefines.h"
#include "RimPlainPlotDataProducer.h"
#include "RimPlotWindow.h"
#include "RiuPlotAxis.h"
@@ -45,7 +46,7 @@ class RimPlotCurve;
///
///
//==================================================================================================
class RimPlot : public QObject, public RimPlotWindow
class RimPlot : public QObject, public RimPlotWindow, public RimPlainPlotDataProducer
{
Q_OBJECT;
CAF_PDM_HEADER_INIT;
@@ -82,7 +83,7 @@ public:
virtual void updateLegend() = 0;
virtual QString asciiDataForPlotExport() const = 0;
QString asciiDataForPlotExport() const override = 0;
virtual void reattachAllCurves() = 0;
virtual void detachAllCurves() = 0;
@@ -0,0 +1,35 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2026 Equinor ASA
//
// ResInsight 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.
//
// ResInsight 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.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include <vector>
class RimPlot;
//==================================================================================================
/// Capability mixin: a composite plot window that exposes a set of child RimPlot
/// instances to be exported as individual text dialogs by the "Show Plot Data" feature.
//==================================================================================================
class RimReportPlotGroup
{
public:
virtual ~RimReportPlotGroup() = default;
virtual std::vector<RimPlot*> childPlotsForTextExport() const = 0;
};
@@ -0,0 +1,35 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2026 Equinor ASA
//
// ResInsight 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.
//
// ResInsight 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.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include <memory>
class RimTabbedTextProvider;
//==================================================================================================
/// Capability mixin: a plot type that can produce a tabbed text representation
/// for the "Show Plot Data" feature. Only opt-in plot types inherit this.
//==================================================================================================
class RimTabbedTextProducer
{
public:
virtual ~RimTabbedTextProducer() = default;
virtual std::unique_ptr<RimTabbedTextProvider> createTabbedTextProvider() const = 0;
};
@@ -0,0 +1,37 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2026 Equinor ASA
//
// ResInsight 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.
//
// ResInsight 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.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include <QString>
//==================================================================================================
/// Abstract data source for a tabbed text dialog. One instance feeds one dialog.
/// The owning dialog queries these methods lazily as the user switches tabs.
//==================================================================================================
class RimTabbedTextProvider
{
public:
virtual ~RimTabbedTextProvider() = default;
virtual bool isValid() const = 0;
virtual QString description() const = 0;
virtual QString tabTitle( int tabIndex ) const = 0;
virtual QString tabText( int tabIndex ) const = 0;
virtual int tabCount() const = 0;
};
@@ -12,6 +12,7 @@ set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RimSummaryPlotAxisFormatter.h
${CMAKE_CURRENT_LIST_DIR}/RimSummaryCurveCollection.h
${CMAKE_CURRENT_LIST_DIR}/RimSummaryPlot.h
${CMAKE_CURRENT_LIST_DIR}/RimSummaryPlotTextProvider.h
${CMAKE_CURRENT_LIST_DIR}/RimSummaryPlotCollection.h
${CMAKE_CURRENT_LIST_DIR}/RimSummaryCrossPlotCollection.h
${CMAKE_CURRENT_LIST_DIR}/RimSummaryTimeAxisProperties.h
@@ -71,6 +72,7 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RimSummaryPlotAxisFormatter.cpp
${CMAKE_CURRENT_LIST_DIR}/RimSummaryCurveCollection.cpp
${CMAKE_CURRENT_LIST_DIR}/RimSummaryPlot.cpp
${CMAKE_CURRENT_LIST_DIR}/RimSummaryPlotTextProvider.cpp
${CMAKE_CURRENT_LIST_DIR}/RimSummaryPlotCollection.cpp
${CMAKE_CURRENT_LIST_DIR}/RimSummaryCrossPlotCollection.cpp
${CMAKE_CURRENT_LIST_DIR}/RimSummaryTimeAxisProperties.cpp
@@ -51,6 +51,7 @@
#include "RimSummaryPlotAxisFormatter.h"
#include "RimSummaryPlotControls.h"
#include "RimSummaryPlotNameHelper.h"
#include "RimSummaryPlotTextProvider.h"
#include "RimSummaryTimeAxisProperties.h"
#include "Summary/RiaSummaryAddressCollectionTools.h"
#include "Summary/RiaSummaryCurveDefinition.h"
@@ -328,6 +329,14 @@ QString RimSummaryPlot::asciiDataForPlotExport() const
return asciiDataForSummaryPlotExport( RiaDefines::DateTimePeriod::YEAR, false );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::unique_ptr<RimTabbedTextProvider> RimSummaryPlot::createTabbedTextProvider() const
{
return std::make_unique<RimSummaryPlotTextProvider>( this );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -24,6 +24,7 @@
#include "RimPlot.h"
#include "RimPlotAxisProperties.h"
#include "RimSummaryDataSourceStepping.h"
#include "RimTabbedTextProducer.h"
#include "RiuPlotWidget.h"
#include "RiuSummaryPlot.h"
@@ -75,7 +76,7 @@ class QKeyEvent;
///
///
//==================================================================================================
class RimSummaryPlot : public RimPlot, public RimSummaryDataSourceStepping
class RimSummaryPlot : public RimPlot, public RimSummaryDataSourceStepping, public RimTabbedTextProducer
{
Q_OBJECT;
CAF_PDM_HEADER_INIT;
@@ -140,6 +141,8 @@ public:
QString asciiDataForPlotExport() const override;
QString asciiDataForSummaryPlotExport( RiaDefines::DateTimePeriod resamplingPeriod, bool showTimeAsLongString ) const;
std::unique_ptr<RimTabbedTextProvider> createTabbedTextProvider() const override;
std::vector<RimSummaryCurve*> summaryAndEnsembleCurves() const;
std::set<RiaSummaryCurveDefinition> summaryAndEnsembleCurveDefinitions() const;
std::vector<RimSummaryCurve*> summaryCurves() const;
@@ -0,0 +1,108 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2026 Equinor ASA
//
// ResInsight 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.
//
// ResInsight 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.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RimSummaryPlotTextProvider.h"
#include "RiaDateTimeDefines.h"
#include "RiaPreferencesSummary.h"
#include "RiaQDateTimeTools.h"
#include "RimSummaryPlot.h"
#include "cafAssert.h"
#include <vector>
namespace
{
static std::vector<RiaDefines::DateTimePeriod> supportedTabs()
{
return { RiaDefines::DateTimePeriod::NONE,
RiaDefines::DateTimePeriod::YEAR,
RiaDefines::DateTimePeriod::HALFYEAR,
RiaDefines::DateTimePeriod::QUARTER,
RiaDefines::DateTimePeriod::MONTH,
RiaDefines::DateTimePeriod::WEEK,
RiaDefines::DateTimePeriod::DAY,
RiaDefines::DateTimePeriod::HOUR,
RiaDefines::DateTimePeriod::MINUTE };
}
} // namespace
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimSummaryPlotTextProvider::RimSummaryPlotTextProvider( const RimSummaryPlot* summaryPlot )
: m_summaryPlot( summaryPlot )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimSummaryPlotTextProvider::isValid() const
{
return m_summaryPlot.notNull();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimSummaryPlotTextProvider::description() const
{
CAF_ASSERT( m_summaryPlot.notNull() && "Need to check that provider is valid" );
return m_summaryPlot->description();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimSummaryPlotTextProvider::tabTitle( int tabIndex ) const
{
auto allTabs = supportedTabs();
CAF_ASSERT( tabIndex < static_cast<int>( allTabs.size() ) );
RiaDefines::DateTimePeriod timePeriod = allTabs[tabIndex];
if ( timePeriod == RiaDefines::DateTimePeriod::NONE )
{
return "No Resampling";
}
return QString( "%1" ).arg( RiaQDateTimeTools::dateTimePeriodName( timePeriod ) );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimSummaryPlotTextProvider::tabText( int tabIndex ) const
{
CAF_ASSERT( m_summaryPlot.notNull() && "Need to check that provider is valid" );
auto allTabs = supportedTabs();
CAF_ASSERT( tabIndex < static_cast<int>( allTabs.size() ) );
RiaDefines::DateTimePeriod timePeriod = allTabs[tabIndex];
RiaPreferencesSummary* prefs = RiaPreferencesSummary::current();
return m_summaryPlot->asciiDataForSummaryPlotExport( timePeriod, prefs->showSummaryTimeAsLongString() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int RimSummaryPlotTextProvider::tabCount() const
{
return static_cast<int>( supportedTabs().size() );
}
@@ -0,0 +1,43 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2026 Equinor ASA
//
// ResInsight 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.
//
// ResInsight 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.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RimTabbedTextProvider.h"
#include "cafPdmPointer.h"
class RimSummaryPlot;
//==================================================================================================
/// Tabbed text provider for a RimSummaryPlot. Each tab corresponds to a resampling period.
//==================================================================================================
class RimSummaryPlotTextProvider : public RimTabbedTextProvider
{
public:
explicit RimSummaryPlotTextProvider( const RimSummaryPlot* summaryPlot );
bool isValid() const override;
QString description() const override;
QString tabTitle( int tabIndex ) const override;
QString tabText( int tabIndex ) const override;
int tabCount() const override;
private:
caf::PdmConstPointer<RimSummaryPlot> m_summaryPlot;
};
@@ -20,9 +20,7 @@
#include "RiuTextDialog.h"
#include "RiuTools.h"
#include "RiaQDateTimeTools.h"
#include "SummaryPlotCommands/RicAsciiExportSummaryPlotFeature.h"
#include "RimTabbedTextProvider.h"
#include "cafCmdFeature.h"
@@ -33,7 +31,7 @@
#include <QMenu>
#include <QTabWidget>
#include <cvfAssert.h>
#include <cafAssert.h>
//--------------------------------------------------------------------------------------------------
///
@@ -96,30 +94,6 @@ void RiuQPlainTextEdit::slotSelectAll()
selectAll();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuQPlainTextEdit::slotExportToFile()
{
// Get dialog
RiuTabbedTextDialog* dialog = nullptr;
auto curr = parent();
while ( dialog == nullptr )
{
if ( !curr ) break;
dialog = dynamic_cast<RiuTabbedTextDialog*>( curr );
if ( dialog ) break;
curr = curr->parent();
}
if ( dialog )
{
QString defaultDir = RicAsciiExportSummaryPlotFeature::defaultExportDir();
auto fileName = RicAsciiExportSummaryPlotFeature::getFileNameFromUserDialog( dialog->description(), defaultDir );
RicAsciiExportSummaryPlotFeature::exportTextToFile( fileName, toPlainText() );
}
}
//--------------------------------------------------------------------------------------------------
///
///
@@ -188,15 +162,15 @@ void RiuTextDialog::contextMenuEvent( QContextMenuEvent* event )
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiuTabbedTextDialog::RiuTabbedTextDialog( RiuTabbedTextProvider* textProvider, QWidget* parent /*= nullptr*/ )
: m_textProvider( textProvider )
, QDialog( parent, RiuTools::defaultDialogFlags() )
RiuTabbedTextDialog::RiuTabbedTextDialog( std::unique_ptr<RimTabbedTextProvider> textProvider, QWidget* parent /*= nullptr*/ )
: QDialog( parent, RiuTools::defaultDialogFlags() )
, m_textProvider( std::move( textProvider ) )
{
m_tabWidget = new QTabWidget( this );
connect( m_tabWidget, SIGNAL( currentChanged( int ) ), this, SLOT( slotTabChanged( int ) ) );
CVF_ASSERT( m_textProvider->isValid() );
CAF_ASSERT( m_textProvider && m_textProvider->isValid() );
setWindowTitle( m_textProvider->description() );
for ( int tabIndex = 0; tabIndex < m_textProvider->tabCount(); ++tabIndex )
@@ -224,6 +198,11 @@ RiuTabbedTextDialog::RiuTabbedTextDialog( RiuTabbedTextProvider* textProvider, Q
updateTabText();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiuTabbedTextDialog::~RiuTabbedTextDialog() = default;
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -293,6 +272,17 @@ void RiuTabbedTextDialog::slotTabChanged( int index )
redrawText();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuTabbedTextDialog::slotExportToFile()
{
auto textEdit = currentTextEdit();
if ( !textEdit ) return;
emit exportToFileRequested( description(), textEdit->toPlainText() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -329,7 +319,7 @@ void RiuTabbedTextDialog::contextMenuEvent( QContextMenuEvent* event )
actionToSetup->setText( "Export to File..." );
connect( actionToSetup, SIGNAL( triggered() ), textEdit, SLOT( slotExportToFile() ) );
connect( actionToSetup, SIGNAL( triggered() ), this, SLOT( slotExportToFile() ) );
menu.addAction( actionToSetup );
}
@@ -20,12 +20,12 @@
#include <QDialog>
#include <QPlainTextEdit>
#include <QPointer>
#include <functional>
#include <memory>
#include <vector>
class QTabWidget;
class RimSummaryPlot;
class RimTabbedTextProvider;
//--------------------------------------------------------------------------------------------------
///
@@ -45,7 +45,6 @@ protected:
private slots:
void slotCopyContentToClipboard();
void slotSelectAll();
void slotExportToFile();
};
//--------------------------------------------------------------------------------------------------
@@ -67,18 +66,6 @@ protected:
void contextMenuEvent( QContextMenuEvent* ) override;
};
class RiuTabbedTextProvider : public QObject
{
Q_OBJECT
public:
virtual bool isValid() const = 0;
virtual QString description() const = 0;
virtual QString tabTitle( int tabIndex ) const = 0;
virtual QString tabText( int tabIndex ) const = 0;
virtual int tabCount() const = 0;
};
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -87,21 +74,26 @@ class RiuTabbedTextDialog : public QDialog
Q_OBJECT
public:
explicit RiuTabbedTextDialog( RiuTabbedTextProvider* textProvider, QWidget* parent = nullptr );
explicit RiuTabbedTextDialog( std::unique_ptr<RimTabbedTextProvider> textProvider, QWidget* parent = nullptr );
~RiuTabbedTextDialog() override;
QString description() const;
void redrawText();
signals:
void exportToFileRequested( const QString& title, const QString& text );
private:
RiuQPlainTextEdit* currentTextEdit() const;
void updateTabText();
QTabWidget* m_tabWidget;
QPointer<RiuTabbedTextProvider> m_textProvider;
std::vector<QString> m_tabTexts;
QTabWidget* m_tabWidget;
std::unique_ptr<RimTabbedTextProvider> m_textProvider;
std::vector<QString> m_tabTexts;
private slots:
void slotTabChanged( int index );
void slotExportToFile();
protected:
void contextMenuEvent( QContextMenuEvent* ) override;
@@ -128,6 +128,56 @@ public:
}
};
//==================================================================================================
/// Guarded const pointer to a PdmObject.
///
/// Same lifetime-guarding behavior as PdmPointer<T>, but exposes only const access to the target.
/// Use for non-owning read-only observers (text providers, renderers, part managers) that hold
/// a reference to a logically-const PdmObject. Construction from a const T* does not require
/// the caller to const_cast.
//==================================================================================================
template <class T>
class PdmConstPointer
{
PdmPointer<T> m_ptr;
public:
inline PdmConstPointer() = default;
inline PdmConstPointer( const T* p )
: m_ptr( const_cast<T*>( p ) )
{
}
inline PdmConstPointer( const PdmConstPointer<T>& p ) = default;
inline PdmConstPointer<T>& operator=( const PdmConstPointer<T>& p ) = default;
inline PdmConstPointer( const PdmPointer<T>& p )
: m_ptr( p )
{
}
const T* p() const { return m_ptr.p(); }
bool isNull() const { return m_ptr.isNull(); }
bool notNull() const { return m_ptr.notNull(); }
operator const T*() const { return m_ptr.p(); }
const T& operator*() const { return *m_ptr.p(); }
const T* operator->() const { return m_ptr.p(); }
PdmConstPointer<T>& operator=( const T* p )
{
m_ptr = const_cast<T*>( p );
return *this;
}
template <class S>
bool operator==( const PdmConstPointer<S>& rhs ) const
{
return m_ptr.rawPtr() == rhs.rawPtr();
}
PdmObjectHandle* rawPtr() const { return m_ptr.rawPtr(); }
};
} // End of namespace caf
#include <QMetaType>