From e72f57072c06622c195dd54a0f5a86cd095d7db8 Mon Sep 17 00:00:00 2001 From: Gaute Lindkvist Date: Mon, 11 Mar 2019 11:39:23 +0100 Subject: [PATCH] #4185 Implement data export for Grid Cross Plot --- .../RicShowPlotDataFeature.cpp | 171 +++++++++++++++--- .../RicShowPlotDataFeature.h | 4 +- .../RicExportSelectedWellPathsFeature.cpp | 2 +- .../RifEclipseDataTableFormatter.cpp | 6 +- .../GridCrossPlots/RimGridCrossPlot.cpp | 41 +++++ .../GridCrossPlots/RimGridCrossPlot.h | 5 +- .../GridCrossPlots/RimGridCrossPlotCurve.h | 1 + .../RimGridCrossPlotCurveSet.cpp | 132 +++++++++++--- .../GridCrossPlots/RimGridCrossPlotCurveSet.h | 8 +- .../ProjectDataModel/RimPlotCurve.cpp | 24 ++- .../ProjectDataModel/RimPlotCurve.h | 5 +- .../UserInterface/RiuGridCrossQwtPlot.cpp | 24 +++ .../UserInterface/RiuGridCrossQwtPlot.h | 1 + .../UserInterface/RiuTextDialog.cpp | 105 ++++++----- ApplicationCode/UserInterface/RiuTextDialog.h | 37 ++-- 15 files changed, 432 insertions(+), 134 deletions(-) diff --git a/ApplicationCode/Commands/ApplicationCommands/RicShowPlotDataFeature.cpp b/ApplicationCode/Commands/ApplicationCommands/RicShowPlotDataFeature.cpp index abd4d7f789..47913bb6d6 100644 --- a/ApplicationCode/Commands/ApplicationCommands/RicShowPlotDataFeature.cpp +++ b/ApplicationCode/Commands/ApplicationCommands/RicShowPlotDataFeature.cpp @@ -20,6 +20,9 @@ #include "RiaApplication.h" +#include "RimGridCrossPlot.h" +#include "RimGridCrossPlotCurve.h" +#include "RimGridCrossPlotCurveSet.h" #include "RimProject.h" #include "RimSummaryCrossPlot.h" #include "RimSummaryPlot.h" @@ -28,6 +31,8 @@ #include "RiuPlotMainWindow.h" #include "RiuTextDialog.h" +#include "cafPdmPointer.h" +#include "cafProgressInfo.h" #include "cafSelectionManagerTools.h" #include @@ -35,6 +40,128 @@ CAF_CMD_SOURCE_INIT(RicShowPlotDataFeature, "RicShowPlotDataFeature"); +//-------------------------------------------------------------------------------------------------- +/// Private text provider class for summary plots +//-------------------------------------------------------------------------------------------------- +class RiuTabbedSummaryPlotTextProvider : public RiuTabbedTextProvider +{ +public: + RiuTabbedSummaryPlotTextProvider(RimSummaryPlot* summaryPlot) + : m_summaryPlot(summaryPlot) + { + } + + virtual 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()); + DateTimePeriod timePeriod = allTabs[tabIndex]; + if (timePeriod == DateTimePeriod::NONE) + { + return "No Resampling"; + } + else + { + return QString("Plot Data, %1").arg(RiaQDateTimeTools::dateTimePeriodName(timePeriod)); + } + } + + QString tabText(int tabIndex) const override + { + CVF_ASSERT(m_summaryPlot.notNull() && "Need to check that provider is valid"); + + DateTimePeriod timePeriod = indexToPeriod(tabIndex); + + if (m_summaryPlot->containsResamplableCurves()) + { + return m_summaryPlot->asciiDataForPlotExport(timePeriod); + } + else + { + return m_summaryPlot->asciiDataForPlotExport(); + } + } + + int tabCount() const override + { + return (int)tabs().size(); + } + +private: + static DateTimePeriod indexToPeriod(int tabIndex) + { + auto allTabs = tabs(); + CVF_ASSERT(tabIndex < (int)allTabs.size()); + DateTimePeriod timePeriod = allTabs[tabIndex]; + return timePeriod; + } + + static std::vector tabs() + { + std::vector dateTimePeriods = RiaQDateTimeTools::dateTimePeriods(); + dateTimePeriods.erase(std::remove(dateTimePeriods.begin(), dateTimePeriods.end(), DateTimePeriod::DECADE), + dateTimePeriods.end()); + return dateTimePeriods; + } + +private: + caf::PdmPointer m_summaryPlot; +}; + +//-------------------------------------------------------------------------------------------------- +/// Private text provider class for grid cross plots +//-------------------------------------------------------------------------------------------------- +class RiuTabbedGridCrossPlotTextProvider : public RiuTabbedTextProvider +{ +public: + RiuTabbedGridCrossPlotTextProvider(RimGridCrossPlot* crossPlot) + : m_crossPlot(crossPlot) + { + } + + virtual bool isValid() const override + { + return m_crossPlot.notNull(); + } + + virtual QString description() const override + { + CVF_ASSERT(m_crossPlot.notNull() && "Need to check that provider is valid"); + return m_crossPlot->createAutoName(); + } + + virtual QString tabTitle(int tabIndex) const override + { + CVF_ASSERT(m_crossPlot.notNull() && "Need to check that provider is valid"); + return m_crossPlot->asciiTitleForPlotExport(tabIndex); + } + + virtual QString tabText(int tabIndex) const override + { + CVF_ASSERT(m_crossPlot.notNull() && "Need to check that provider is valid"); + return m_crossPlot->asciiDataForPlotExport(tabIndex); + } + + virtual int tabCount() const override + { + CVF_ASSERT(m_crossPlot.notNull() && "Need to check that provider is valid"); + return (int)m_crossPlot->curveSets().size(); + } + +private: + caf::PdmPointer m_crossPlot; +}; //-------------------------------------------------------------------------------------------------- /// @@ -62,6 +189,9 @@ bool RicShowPlotDataFeature::isCommandEnabled() auto wellLogPlots = caf::selectedObjectsByType(); if (wellLogPlots.size() > 0) return true; + auto gridCrossPlots = caf::selectedObjectsByType(); + if (gridCrossPlots.size() > 0) return true; + return false; } @@ -72,10 +202,10 @@ void RicShowPlotDataFeature::onActionTriggered(bool isChecked) { this->disableModelChangeContribution(); - std::vector selectedSummaryPlots = caf::selectedObjectsByType(); - std::vector wellLogPlots = caf::selectedObjectsByType(); - - if (selectedSummaryPlots.size() == 0 && wellLogPlots.size() == 0) + std::vector selectedSummaryPlots = caf::selectedObjectsByType(); + std::vector wellLogPlots = caf::selectedObjectsByType(); + std::vector crossPlots = caf::selectedObjectsByType(); + if (selectedSummaryPlots.size() == 0 && wellLogPlots.size() == 0 && crossPlots.size() == 0) { CVF_ASSERT(false); @@ -87,26 +217,22 @@ void RicShowPlotDataFeature::onActionTriggered(bool isChecked) for (RimSummaryPlot* summaryPlot : selectedSummaryPlots) { - QString title = summaryPlot->description(); - - if (summaryPlot->containsResamplableCurves()) - { - RicShowPlotDataFeature::showTabbedTextWindow(title, [summaryPlot](DateTimePeriod period) { return summaryPlot->asciiDataForPlotExport(period); }); - } - else - { - QString text = summaryPlot->asciiDataForPlotExport(); - RicShowPlotDataFeature::showTextWindow(title, text); - } + auto textProvider = new RiuTabbedSummaryPlotTextProvider(summaryPlot); + RicShowPlotDataFeature::showTabbedTextWindow(textProvider); } for (RimWellLogPlot* wellLogPlot : wellLogPlots) { QString title = wellLogPlot->description(); QString text = wellLogPlot->asciiDataForPlotExport(); - RicShowPlotDataFeature::showTextWindow(title, text); } + + for (RimGridCrossPlot* crossPlot : crossPlots) + { + auto textProvider = new RiuTabbedGridCrossPlotTextProvider(crossPlot); + RicShowPlotDataFeature::showTabbedTextWindow(textProvider); + } } //-------------------------------------------------------------------------------------------------- @@ -118,24 +244,19 @@ void RicShowPlotDataFeature::setupActionLook(QAction* actionToSetup) actionToSetup->setIcon(QIcon(":/PlotWindow24x24.png")); } - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RicShowPlotDataFeature::showTabbedTextWindow(const QString& title, std::function textProvider) +void RicShowPlotDataFeature::showTabbedTextWindow(RiuTabbedTextProvider* textProvider) { RiuPlotMainWindow* plotwindow = RiaApplication::instance()->mainPlotWindow(); CVF_ASSERT(plotwindow); - RiuShowTabbedPlotDataDialog* textWidget = new RiuShowTabbedPlotDataDialog(); + RiuTabbedTextDialog* textWidget = new RiuTabbedTextDialog(textProvider); textWidget->setMinimumSize(800, 600); - - textWidget->setWindowTitle(title); - textWidget->setDescription(title); - textWidget->setTextProvider(textProvider); - textWidget->show(); - plotwindow->addToTemporaryWidgets(textWidget); + textWidget->show(); + textWidget->redrawText(); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/ApplicationCommands/RicShowPlotDataFeature.h b/ApplicationCode/Commands/ApplicationCommands/RicShowPlotDataFeature.h index 27284bcdfd..a36fde06f8 100644 --- a/ApplicationCode/Commands/ApplicationCommands/RicShowPlotDataFeature.h +++ b/ApplicationCode/Commands/ApplicationCommands/RicShowPlotDataFeature.h @@ -24,6 +24,8 @@ #include +class RiuTabbedTextProvider; + //================================================================================================== /// //================================================================================================== @@ -38,7 +40,7 @@ protected: void setupActionLook( QAction* actionToSetup ) override; public: - static void showTabbedTextWindow(const QString& title, std::function textProvider); + static void showTabbedTextWindow(RiuTabbedTextProvider* textProvider); static void showTextWindow(const QString& title, const QString& text); }; diff --git a/ApplicationCode/Commands/ExportCommands/RicExportSelectedWellPathsFeature.cpp b/ApplicationCode/Commands/ExportCommands/RicExportSelectedWellPathsFeature.cpp index 9ad10316f7..efe978e6e3 100644 --- a/ApplicationCode/Commands/ExportCommands/RicExportSelectedWellPathsFeature.cpp +++ b/ApplicationCode/Commands/ExportCommands/RicExportSelectedWellPathsFeature.cpp @@ -106,7 +106,7 @@ void RicExportSelectedWellPathsFeature::writeWellPathGeometryToStream(QTextStrea double endMd = wellPathGeom->measureDepths().back(); RifEclipseDataTableFormatter formatter(stream); - formatter.setCommentPrefix("#"); + formatter.setCommentPrefix("# "); formatter.setTableRowPrependText(" "); if (writeProjectInfo) diff --git a/ApplicationCode/FileInterface/RifEclipseDataTableFormatter.cpp b/ApplicationCode/FileInterface/RifEclipseDataTableFormatter.cpp index 5b82b06962..3209e03edc 100644 --- a/ApplicationCode/FileInterface/RifEclipseDataTableFormatter.cpp +++ b/ApplicationCode/FileInterface/RifEclipseDataTableFormatter.cpp @@ -32,7 +32,7 @@ RifEclipseDataTableFormatter::RifEclipseDataTableFormatter(QTextStream& out) , m_colSpacing(5) , m_tableRowPrependText(" ") , m_tableRowAppendText(" /") - , m_commentPrefix("--") + , m_commentPrefix("-- ") , m_maxDataRowWidth(MAX_ECLIPSE_DATA_ROW_WIDTH) { } @@ -154,7 +154,7 @@ void RifEclipseDataTableFormatter::outputBuffer() { if (!m_columns.empty() && !isAllHeadersEmpty(m_columns)) { - m_out << m_commentPrefix << " "; + m_out << m_commentPrefix; for (size_t i = 0u; i < m_columns.size(); ++i) { m_out << formatColumn(m_columns[i].title, i); @@ -206,7 +206,7 @@ void RifEclipseDataTableFormatter::outputBuffer() //-------------------------------------------------------------------------------------------------- void RifEclipseDataTableFormatter::outputComment(RifEclipseOutputTableLine& comment) { - m_out << m_commentPrefix << " " << comment.data[0] << "\n"; + m_out << m_commentPrefix << comment.data[0] << "\n"; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.cpp b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.cpp index 2d9748d253..6ba69aa215 100644 --- a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.cpp +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.cpp @@ -17,6 +17,7 @@ ///////////////////////////////////////////////////////////////////////////////// #include "RimGridCrossPlot.h" +#include "RifEclipseDataTableFormatter.h" #include "RiuGridCrossQwtPlot.h" #include "RiuPlotMainWindowTools.h" #include "RiuQwtPlotTools.h" @@ -28,6 +29,7 @@ #include "cafPdmUiCheckBoxEditor.h" #include "cafPdmUiTreeOrdering.h" +#include "cafProgressInfo.h" #include "cvfAssert.h" #include "qwt_legend.h" @@ -520,6 +522,45 @@ void RimGridCrossPlot::swapAllAxisProperties() loadDataAndUpdate(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimGridCrossPlot::asciiTitleForPlotExport(int curveSetIndex) const +{ + if ((size_t)curveSetIndex < m_crossPlotCurveSets.size()) + { + return m_crossPlotCurveSets[curveSetIndex]->createAutoName(); + } + return "Data invalid"; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimGridCrossPlot::asciiDataForPlotExport(int curveSetIndex) const +{ + if ((size_t)curveSetIndex < m_crossPlotCurveSets.size()) + { + QString asciiData; + QTextStream stringStream(&asciiData); + + RifEclipseDataTableFormatter formatter(stringStream); + formatter.setCommentPrefix(""); + formatter.setTableRowPrependText(""); + formatter.setTableRowLineAppendText(""); + formatter.setColumnSpacing(3); + + + m_crossPlotCurveSets[curveSetIndex]->exportFormattedData(formatter); + formatter.tableCompleted(); + return asciiData; + } + else + { + return "Data invalid and may have been deleted."; + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.h b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.h index 1005619d42..bd8564c290 100644 --- a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.h +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.h @@ -70,8 +70,10 @@ public: void performAutoNameUpdate() override; void updateCurveNamesAndPlotTitle(); void swapAllAxisProperties(); - + QString asciiTitleForPlotExport(int curveSetIndex) const; + QString asciiDataForPlotExport(int curveSetIndex) const; RiuGridCrossQwtPlot* qwtPlot() const; + public: // Rim2dPlotInterface overrides void updateAxisScaling() override; @@ -112,6 +114,7 @@ private: caf::PdmChildArrayField m_crossPlotCurveSets; QPointer m_qwtPlot; + }; diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurve.h b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurve.h index 58f36171d5..40ef6fc5d8 100644 --- a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurve.h +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurve.h @@ -42,6 +42,7 @@ public: ~RimGridCrossPlotCurve() override = default; void setGroupingInformation(int curveSetIndex, int groupIndex); void setSamples(const std::vector& xValues, const std::vector& yValues); + void updateCurveAppearance() override; int groupIndex() const; diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurveSet.cpp b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurveSet.cpp index 89caba5adc..63e687aab9 100644 --- a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurveSet.cpp +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurveSet.cpp @@ -21,6 +21,8 @@ #include "RiaColorTables.h" #include "RiaLogging.h" +#include "RifEclipseDataTableFormatter.h" + #include "RigActiveCellInfo.h" #include "RigActiveCellsResultAccessor.h" #include "RigCaseCellResultCalculator.h" @@ -44,11 +46,14 @@ #include "RimRegularLegendConfig.h" #include "RimTools.h" +#include "cafCategoryMapper.h" #include "cafColorTable.h" #include "cafPdmUiComboBoxEditor.h" #include "cafPdmUiSliderEditor.h" #include "cafPdmUiTreeOrdering.h" +#include "cafProgressInfo.h" #include "cvfScalarMapper.h" +#include "cvfqtUtils.h" #include @@ -210,7 +215,11 @@ QString RimGridCrossPlotCurveSet::createAutoName() const //-------------------------------------------------------------------------------------------------- QString RimGridCrossPlotCurveSet::groupTitle() const { - return QString("Grouping by %1").arg(groupParameter()); + if (m_grouping != NO_GROUPING) + { + return QString("Grouped by %1").arg(groupParameter()); + } + return ""; } //-------------------------------------------------------------------------------------------------- @@ -410,6 +419,7 @@ void RimGridCrossPlotCurveSet::onLoadDataAndUpdate(bool updateParentPlot) //-------------------------------------------------------------------------------------------------- void RimGridCrossPlotCurveSet::createCurves(const RigEclipseCrossPlotResult& result) { + m_groupedResults.clear(); if (!groupingEnabled()) { const caf::ColorTable& colors = RiaColorTables::contrastCategoryPaletteColors(); @@ -422,11 +432,10 @@ void RimGridCrossPlotCurveSet::createCurves(const RigEclipseCrossPlotResult& res curve->updateCurveAppearance(); curve->updateUiIconFromPlotSymbol(); m_crossPlotCurves.push_back(curve); + m_groupedResults[0] = result; } else { - std::map, std::vector>> groupedResults; - std::vector tickValues; if (groupingByCategoryResult()) @@ -438,8 +447,13 @@ void RimGridCrossPlotCurveSet::createCurves(const RigEclipseCrossPlotResult& res ? static_cast(result.groupValuesContinuous[i]) : result.groupValuesDiscrete[i]; - groupedResults[categoryNum].first.push_back(result.xValues[i]); - groupedResults[categoryNum].second.push_back(result.yValues[i]); + m_groupedResults[categoryNum].xValues.push_back(result.xValues[i]); + m_groupedResults[categoryNum].yValues.push_back(result.yValues[i]); + if (!result.groupValuesContinuous.empty()) + m_groupedResults[categoryNum].groupValuesContinuous.push_back(result.groupValuesContinuous[i]); + if (!result.groupValuesDiscrete.empty()) + m_groupedResults[categoryNum].groupValuesDiscrete.push_back(result.groupValuesDiscrete[i]); + } } else @@ -450,13 +464,17 @@ void RimGridCrossPlotCurveSet::createCurves(const RigEclipseCrossPlotResult& res { auto upperBoundIt = std::lower_bound(tickValues.begin(), tickValues.end(), result.groupValuesContinuous[i]); int upperBoundIndex = static_cast(upperBoundIt - tickValues.begin()); - int lowerBoundIndex = std::min((int) tickValues.size() - 2, std::max(0, upperBoundIndex - 1)); - groupedResults[lowerBoundIndex].first.push_back(result.xValues[i]); - groupedResults[lowerBoundIndex].second.push_back(result.yValues[i]); + int categoryNum = std::min((int) tickValues.size() - 2, std::max(0, upperBoundIndex - 1)); + m_groupedResults[categoryNum].xValues.push_back(result.xValues[i]); + m_groupedResults[categoryNum].yValues.push_back(result.yValues[i]); + if (!result.groupValuesContinuous.empty()) + m_groupedResults[categoryNum].groupValuesContinuous.push_back(result.groupValuesContinuous[i]); + if (!result.groupValuesDiscrete.empty()) + m_groupedResults[categoryNum].groupValuesDiscrete.push_back(result.groupValuesDiscrete[i]); } } - for (auto it = groupedResults.rbegin(); it != groupedResults.rend(); ++it) + for (auto it = m_groupedResults.rbegin(); it != m_groupedResults.rend(); ++it) { RimGridCrossPlotCurve* curve = new RimGridCrossPlotCurve(); curve->setGroupingInformation(indexInPlot(), it->first); @@ -468,9 +486,9 @@ void RimGridCrossPlotCurveSet::createCurves(const RigEclipseCrossPlotResult& res { curve->setColor(cvf::Color3f(legendConfig()->scalarMapper()->mapToColor(tickValues[it->first]))); } - curve->setSamples(it->second.first, it->second.second); + curve->setSamples(it->second.xValues, it->second.yValues); curve->showLegend(m_crossPlotCurves.empty()); - curve->setLegendEntryTitle(createAutoName()); + curve->setLegendEntryText(createAutoName()); curve->updateCurveAppearance(); curve->updateUiIconFromPlotSymbol(); m_crossPlotCurves.push_back(curve); @@ -478,6 +496,26 @@ void RimGridCrossPlotCurveSet::createCurves(const RigEclipseCrossPlotResult& res } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimGridCrossPlotCurveSet::createGroupName(size_t groupIndex) const +{ + if (groupingByCategoryResult()) + { + return legendConfig()->categoryNameFromCategoryValue(groupIndex); + } + else + { + std::vector tickValues; + legendConfig()->scalarMapper()->majorTickValues(&tickValues); + double lowerLimit = tickValues[groupIndex]; + double upperLimit = + groupIndex + 1u < tickValues.size() ? tickValues[groupIndex + 1u] : std::numeric_limits::infinity(); + return QString("%1 [%2, %3]").arg(groupParameter()).arg(lowerLimit).arg(upperLimit); + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -786,6 +824,56 @@ void RimGridCrossPlotCurveSet::swapAxisProperties(bool updatePlot) loadDataAndUpdate(updatePlot); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotCurveSet::exportFormattedData(RifEclipseDataTableFormatter& formatter) const +{ + if (m_groupedResults.empty()) + return; + + if (m_grouping != NO_GROUPING) + { + std::vector header = {RifEclipseOutputTableColumn("X"), + RifEclipseOutputTableColumn("Y"), + RifEclipseOutputTableColumn("Group Index"), + RifEclipseOutputTableColumn("Group Description")}; + + formatter.header(header); + } + else + { + std::vector header = {RifEclipseOutputTableColumn("X"), RifEclipseOutputTableColumn("Y")}; + formatter.header(header); + } + + caf::ProgressInfo progress(m_groupedResults.size(), "Gathering Data Points"); + for (auto it = m_groupedResults.begin(); it != m_groupedResults.end(); ++it) + { + int groupIndex = it->first; + RigEclipseCrossPlotResult res = it->second; + + for (size_t i = 0; i < it->second.xValues.size(); ++i) + { + if (m_grouping() == NO_GROUPING) + { + formatter.add(res.xValues[i]); + formatter.add(res.yValues[i]); + } + else + { + QString groupName = createGroupName(groupIndex); + formatter.add(res.xValues[i]); + formatter.add(res.yValues[i]); + formatter.add(groupIndex); + formatter.add(groupName); + } + formatter.rowCompleted(); + } + progress.incrementProgress(); + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -809,29 +897,17 @@ void RimGridCrossPlotCurveSet::updateCurveNames(size_t curveSetIndex, size_t cur if (curveSetName.isEmpty()) { if (curveSetCount > 1u) - curveSetName = QString("Curve #%1").arg(curveSetIndex + 1); + curveSetName = QString("Curve Set #%1").arg(curveSetIndex + 1); else - curveSetName = "Curve"; + curveSetName = "Curve Set"; } auto curve = m_crossPlotCurves[i]; if (groupingEnabled()) { - if (groupingByCategoryResult()) - { - curve->setCustomName(legendConfig()->categoryNameFromCategoryValue(curve->groupIndex())); - } - else - { - std::vector tickValues; - legendConfig()->scalarMapper()->majorTickValues(&tickValues); - size_t catIndex = (size_t) curve->groupIndex(); - double lowerLimit = tickValues[catIndex]; - double upperLimit = catIndex + 1u < tickValues.size() - ? tickValues[catIndex + 1u] : std::numeric_limits::infinity(); - curve->setCustomName(QString("%1 [%2, %3]").arg(groupParameter()).arg(lowerLimit).arg(upperLimit)); - } - curve->setLegendEntryTitle(curveSetName); + QString curveGroupName = createGroupName(curve->groupIndex()); + curve->setCustomName(curveGroupName); + curve->setLegendEntryText(curveSetName); } else { diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurveSet.h b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurveSet.h index 414ad6118c..ba988fc179 100644 --- a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurveSet.h +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurveSet.h @@ -18,6 +18,7 @@ #pragma once #include "RigGridCrossPlotCurveGrouping.h" +#include "RigEclipseCrossPlotDataExtractor.h" #include "RimCheckableNamedObject.h" #include "RimNameConfig.h" @@ -34,7 +35,7 @@ #include #include -struct RigEclipseCrossPlotResult; +class RifEclipseDataTableFormatter; class RimCase; class RimGridCrossPlotCurve; class RimGridView; @@ -114,12 +115,14 @@ public: bool groupingByCategoryResult() const; bool groupingEnabled() const; void swapAxisProperties(bool updatePlot); + void exportFormattedData(RifEclipseDataTableFormatter& formatter) const; protected: void initAfterRead() override; void onLoadDataAndUpdate(bool updateParentPlot); void createCurves(const RigEclipseCrossPlotResult& result); + QString createGroupName(size_t curveIndex) const; std::map calculateCellVisibility(RimEclipseCase* eclipseCase) const; @@ -137,6 +140,7 @@ protected: bool hasMultipleTimeSteps() const; private: + caf::PdmPtrField m_case; caf::PdmField m_timeStep; caf::PdmPtrField m_cellFilterView; @@ -148,4 +152,6 @@ private: caf::PdmChildField m_nameConfig; caf::PdmChildArrayField m_crossPlotCurves; + + std::map m_groupedResults; }; diff --git a/ApplicationCode/ProjectDataModel/RimPlotCurve.cpp b/ApplicationCode/ProjectDataModel/RimPlotCurve.cpp index ea4d1695a6..fd6a7d3e0f 100644 --- a/ApplicationCode/ProjectDataModel/RimPlotCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimPlotCurve.cpp @@ -96,8 +96,8 @@ RimPlotCurve::RimPlotCurve() CAF_PDM_InitFieldNoDefault(&m_customCurveName, "CurveDescription", "Custom Name", "", "", ""); m_customCurveName.uiCapability()->setUiHidden(true); - CAF_PDM_InitFieldNoDefault(&m_legendEntryTitle, "LegendDescription", "Legend Name", "", "", ""); - m_legendEntryTitle.uiCapability()->setUiHidden(true); + CAF_PDM_InitFieldNoDefault(&m_legendEntryText, "LegendDescription", "Legend Name", "", "", ""); + m_legendEntryText.uiCapability()->setUiHidden(true); CAF_PDM_InitField(&m_isUsingAutoName, "AutoName", true, "Auto Name", "", "", ""); @@ -219,9 +219,21 @@ void RimPlotCurve::setCustomName(const QString& customName) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimPlotCurve::setLegendEntryTitle(const QString& legendEntryTitle) +QString RimPlotCurve::legendEntryText() const { - m_legendEntryTitle = legendEntryTitle; + if (!m_legendEntryText().isEmpty()) + { + return m_legendEntryText; + } + return m_customCurveName; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotCurve::setLegendEntryText(const QString& legendEntryText) +{ + m_legendEntryText = legendEntryText; } //-------------------------------------------------------------------------------------------------- @@ -378,9 +390,9 @@ void RimPlotCurve::updateCurveName() m_curveName = m_customCurveName; } - if (!m_legendEntryTitle().isEmpty()) + if (!m_legendEntryText().isEmpty()) { - m_qwtPlotCurve->setTitle(m_legendEntryTitle); + m_qwtPlotCurve->setTitle(m_legendEntryText); } else { diff --git a/ApplicationCode/ProjectDataModel/RimPlotCurve.h b/ApplicationCode/ProjectDataModel/RimPlotCurve.h index a11320d6be..f7e2ae6212 100644 --- a/ApplicationCode/ProjectDataModel/RimPlotCurve.h +++ b/ApplicationCode/ProjectDataModel/RimPlotCurve.h @@ -78,7 +78,8 @@ public: QString curveName() const { return m_curveName; } virtual QString curveExportDescription(const RifEclipseSummaryAddress& address = RifEclipseSummaryAddress()) const { return m_curveName; } void setCustomName(const QString& customName); - void setLegendEntryTitle(const QString& legendEntryTitle); + QString legendEntryText() const; + void setLegendEntryText(const QString& legendEntryText); void updateCurveVisibility(bool updateParentPlot); void updateLegendEntryVisibilityAndPlotLegend(); @@ -127,7 +128,7 @@ protected: caf::PdmField m_showLegend; QString m_symbolLabel; caf::PdmField m_symbolSize; - caf::PdmField m_legendEntryTitle; + caf::PdmField m_legendEntryText; caf::PdmField m_isUsingAutoName; caf::PdmField m_curveColor; diff --git a/ApplicationCode/UserInterface/RiuGridCrossQwtPlot.cpp b/ApplicationCode/UserInterface/RiuGridCrossQwtPlot.cpp index be7c5e27df..a90cac1e7a 100644 --- a/ApplicationCode/UserInterface/RiuGridCrossQwtPlot.cpp +++ b/ApplicationCode/UserInterface/RiuGridCrossQwtPlot.cpp @@ -24,8 +24,11 @@ #include "RimGridCrossPlotCurveSet.h" #include "RimRegularLegendConfig.h" +#include "cafCmdFeatureMenuBuilder.h" +#include "cafSelectionManager.h" #include "cafTitledOverlayFrame.h" +#include #include //-------------------------------------------------------------------------------------------------- @@ -207,3 +210,24 @@ bool RiuGridCrossQwtPlot::resizeOverlayItemToFitPlot(caf::TitledOverlayFrame* ov overlayItem->setRenderSize(legendSize); return sizeAltered; } + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuGridCrossQwtPlot::contextMenuEvent(QContextMenuEvent* event) +{ + QMenu menu; + caf::CmdFeatureMenuBuilder menuBuilder; + + caf::SelectionManager::instance()->setSelectedItem(ownerViewWindow()); + + menuBuilder << "RicShowPlotDataFeature"; + + menuBuilder.appendToMenu(&menu); + + if (menu.actions().size() > 0) + { + menu.exec(event->globalPos()); + } +} diff --git a/ApplicationCode/UserInterface/RiuGridCrossQwtPlot.h b/ApplicationCode/UserInterface/RiuGridCrossQwtPlot.h index edae0892be..f7cc3bdc90 100644 --- a/ApplicationCode/UserInterface/RiuGridCrossQwtPlot.h +++ b/ApplicationCode/UserInterface/RiuGridCrossQwtPlot.h @@ -52,6 +52,7 @@ protected: void updateLegendLayout(); void resizeEvent(QResizeEvent *e) override; bool resizeOverlayItemToFitPlot(caf::TitledOverlayFrame* overlayItem); + void contextMenuEvent(QContextMenuEvent*) override; private: std::map, QPointer> m_legendWidgets; }; diff --git a/ApplicationCode/UserInterface/RiuTextDialog.cpp b/ApplicationCode/UserInterface/RiuTextDialog.cpp index f7a87f7582..b6bf705116 100644 --- a/ApplicationCode/UserInterface/RiuTextDialog.cpp +++ b/ApplicationCode/UserInterface/RiuTextDialog.cpp @@ -101,12 +101,12 @@ void RiuQPlainTextEdit::slotSelectAll() void RiuQPlainTextEdit::slotExportToFile() { // Get dialog - RiuShowTabbedPlotDataDialog* dialog = nullptr; + RiuTabbedTextDialog* dialog = nullptr; auto curr = parent(); while (dialog == nullptr) { if (!curr) break; - dialog = dynamic_cast(curr); + dialog = dynamic_cast(curr); if (dialog) break; curr = curr->parent(); } @@ -190,21 +190,19 @@ void RiuTextDialog::contextMenuEvent(QContextMenuEvent* event) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RiuShowTabbedPlotDataDialog::RiuShowTabbedPlotDataDialog(QWidget* parent /*= nullptr*/) - : QDialog(parent, RiuTools::defaultDialogFlags()) +RiuTabbedTextDialog::RiuTabbedTextDialog(RiuTabbedTextProvider* textProvider, QWidget* parent /*= nullptr*/) + : m_textProvider(textProvider), QDialog(parent, RiuTools::defaultDialogFlags()) { m_tabWidget = new QTabWidget(this); connect(m_tabWidget, SIGNAL(currentChanged(int)), this, SLOT(slotTabChanged(int))); - for(auto timePeriod : RiaQDateTimeTools::dateTimePeriods()) + CVF_ASSERT(m_textProvider->isValid()); + this->setWindowTitle(m_textProvider->description()); + + for (int tabIndex = 0; tabIndex < m_textProvider->tabCount(); ++tabIndex) { - if(timePeriod == DateTimePeriod::DECADE) continue; - - QString tabTitle = - timePeriod == DateTimePeriod::NONE ? "No Resampling" : - QString("Plot Data, %1").arg(RiaQDateTimeTools::dateTimePeriodName(timePeriod)); - + QString tabTitle = m_textProvider->tabTitle(tabIndex); RiuQPlainTextEdit* textEdit = new RiuQPlainTextEdit(); textEdit->setReadOnly(true); textEdit->setLineWrapMode(QPlainTextEdit::NoWrap); @@ -218,43 +216,56 @@ RiuShowTabbedPlotDataDialog::RiuShowTabbedPlotDataDialog(QWidget* parent /*= nul m_tabWidget->addTab(textEdit, tabTitle); } + m_tabTexts.resize(m_textProvider->tabCount()); QVBoxLayout* layout = new QVBoxLayout(); layout->addWidget(m_tabWidget); setLayout(layout); + + updateTabText(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RiuShowTabbedPlotDataDialog::setDescription(const QString& description) +QString RiuTabbedTextDialog::description() const { - m_description = description; + if (m_textProvider && m_textProvider->isValid()) + { + return m_textProvider->description(); + } + else + { + return "Data Invalid"; + } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -QString RiuShowTabbedPlotDataDialog::description() const +void RiuTabbedTextDialog::redrawText() { - if (m_description.isEmpty()) return "Plot Data"; - return m_description; + auto textEdit = currentTextEdit(); + auto currIndex = m_tabWidget->currentIndex(); + + textEdit->setPlainText("Populating Text View..."); + textEdit->repaint(); + + if (currIndex < (int)m_tabTexts.size()) + { + if (m_tabTexts[currIndex].isEmpty()) + { + updateTabText(); + } + textEdit->setPlainText(m_tabTexts[currIndex]); + textEdit->repaint(); + } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuShowTabbedPlotDataDialog::setTextProvider(std::function textProvider) -{ - m_textProvider = textProvider; - - updateText(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RiuQPlainTextEdit * RiuShowTabbedPlotDataDialog::currentTextEdit() const +RiuQPlainTextEdit * RiuTabbedTextDialog::currentTextEdit() const { return dynamic_cast(m_tabWidget->currentWidget()); } @@ -262,44 +273,32 @@ RiuQPlainTextEdit * RiuShowTabbedPlotDataDialog::currentTextEdit() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -DateTimePeriod RiuShowTabbedPlotDataDialog::indexToPeriod(int index) -{ - auto currTabTitle = m_tabWidget->tabText(index); - if (currTabTitle.contains(RiaQDateTimeTools::TIMESPAN_DAY_NAME)) return DateTimePeriod::DAY; - if (currTabTitle.contains(RiaQDateTimeTools::TIMESPAN_WEEK_NAME)) return DateTimePeriod::WEEK; - if (currTabTitle.contains(RiaQDateTimeTools::TIMESPAN_MONTH_NAME)) return DateTimePeriod::MONTH; - if (currTabTitle.contains(RiaQDateTimeTools::TIMESPAN_QUARTER_NAME)) return DateTimePeriod::QUARTER; - if (currTabTitle.contains(RiaQDateTimeTools::TIMESPAN_HALFYEAR_NAME)) return DateTimePeriod::HALFYEAR; - if (currTabTitle.contains(RiaQDateTimeTools::TIMESPAN_YEAR_NAME)) return DateTimePeriod::YEAR; - if (currTabTitle.contains(RiaQDateTimeTools::TIMESPAN_DECADE_NAME)) return DateTimePeriod::DECADE; - return DateTimePeriod::NONE; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuShowTabbedPlotDataDialog::updateText() -{ - auto textEdit = currentTextEdit(); +void RiuTabbedTextDialog::updateTabText() +{ auto currIndex = m_tabWidget->currentIndex(); - if (textEdit && textEdit->toPlainText().isEmpty() && m_textProvider) + if (m_textProvider && m_textProvider->isValid() && + m_tabWidget->tabText(currIndex) == m_textProvider->tabTitle(currIndex)) { - textEdit->setPlainText(m_textProvider(indexToPeriod(currIndex))); + m_tabTexts[currIndex] = m_textProvider->tabText(currIndex); + } + else + { + m_tabTexts[currIndex] = "Data Source No Longer Valid"; } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuShowTabbedPlotDataDialog::slotTabChanged(int index) +void RiuTabbedTextDialog::slotTabChanged(int index) { - updateText(); + redrawText(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuShowTabbedPlotDataDialog::contextMenuEvent(QContextMenuEvent* event) +void RiuTabbedTextDialog::contextMenuEvent(QContextMenuEvent* event) { QMenu menu; RiuQPlainTextEdit* textEdit = dynamic_cast(m_tabWidget->currentWidget()); diff --git a/ApplicationCode/UserInterface/RiuTextDialog.h b/ApplicationCode/UserInterface/RiuTextDialog.h index f666ef066d..de1979ce35 100644 --- a/ApplicationCode/UserInterface/RiuTextDialog.h +++ b/ApplicationCode/UserInterface/RiuTextDialog.h @@ -22,6 +22,7 @@ #include #include +#include #include @@ -67,28 +68,38 @@ protected: }; -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -class RiuShowTabbedPlotDataDialog : public QDialog +class RiuTabbedTextProvider : public QObject { Q_OBJECT public: - explicit RiuShowTabbedPlotDataDialog(QWidget* parent = nullptr); + 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; +}; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +class RiuTabbedTextDialog : public QDialog +{ + Q_OBJECT + +public: + explicit RiuTabbedTextDialog(RiuTabbedTextProvider* textProvider, QWidget* parent = nullptr); - void setDescription(const QString& description); QString description() const; - void setTextProvider(std::function textProvider); + void redrawText(); private: - RiuQPlainTextEdit * currentTextEdit() const; - DateTimePeriod indexToPeriod(int index); - void updateText(); + RiuQPlainTextEdit* currentTextEdit() const; + void updateTabText(); - QTabWidget* m_tabWidget; - QString m_description; - std::function m_textProvider; + QTabWidget* m_tabWidget; + QPointer m_textProvider; + std::vector m_tabTexts; private slots: void slotTabChanged(int index);